Skip to content

fix(msteams): prevent toPluginJsonValue from crashing on unserializable values#111823

Open
wanyongstar wants to merge 1 commit into
openclaw:mainfrom
wanyongstar:fix/msteams-guard-toPluginJsonValue
Open

fix(msteams): prevent toPluginJsonValue from crashing on unserializable values#111823
wanyongstar wants to merge 1 commit into
openclaw:mainfrom
wanyongstar:fix/msteams-guard-toPluginJsonValue

Conversation

@wanyongstar

@wanyongstar wanyongstar commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

toPluginJsonValue in the MSTeams extension serializes plugin state values through JSON.stringify + JSON.parse without guarding against BigInt values or circular references. When a nested BigInt (e.g. a message ID) or circular structure reaches the helper, JSON.stringify throws an unhandled TypeError that crashes the caller before the state can be persisted to SQLite.

The function currently has no replacer, no catch guard, and no JSON-safe fallback -- it either produces valid JSON or throws, and when it throws the state write is silently lost.

Evidence

OLD (current main): crash at toPluginJsonValue, state write never happens

--- OLD with BigInt: state write fails ---
CRASH at toPluginJsonValue: Do not know how to serialize a BigInt
State write NEVER happens - caller crashes

NEW (this PR): JSON-safe replacer, state round-trip succeeds

Normal poll state (baseline):

1. toPluginJsonValue result: {"pollId":"abc","choice":"yes"}
2. SQLite write (JSON): OK, 31 bytes
3. SQLite read (parse): OK
4. Round-trip SUCCESS

BigInt poll state (the fixed scenario):

1. toPluginJsonValue result: {"pollId":"abc","messageId":"1","count":"42"}
2. SQLite write (JSON): OK, 45 bytes
3. SQLite read (parse): OK
4. Round-trip SUCCESS

Circular reference state (safe fallback):

1. toPluginJsonValue result: {}
2. SQLite write (JSON): OK, 2 bytes
3. SQLite read (parse): OK
4. Round-trip SUCCESS

Mixed BigInt + normal values (nested):

1. toPluginJsonValue result: {"pollId":"abc","metadata":{"count":"1","score":"100"},"users":["u1","u2"]}
2. SQLite write (JSON): OK, 75 bytes
3. SQLite read (parse): OK
4. Round-trip SUCCESS

What Changed

Replaced the bare JSON.stringify(value) / JSON.parse(serialized) round-trip with:

  1. BigInt to String replacer: JSON.stringify(value, (_key, val) => typeof val === "bigint" ? String(val) : val) converts BigInt values to strings during serialization so nested BigInts (message IDs, counts, etc.) become JSON-safe
  2. try/catch guard: structural failures (circular references) fall back to {} instead of crashing

The return value is now always JSON-safe: it can be written to SQLite and read back without a deferred serialization failure.

File: extensions/msteams/src/sqlite-state.ts
Diff: +8 / -2 (add replacer + try/catch + fallback)

@openclaw-barnacle openclaw-barnacle Bot added channel: msteams Channel integration: msteams size: XS triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. and removed triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. labels Jul 20, 2026
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. labels Jul 20, 2026
@clawsweeper

clawsweeper Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 20, 2026, 8:30 AM ET / 12:30 UTC.

Summary
Wraps the MSTeams toPluginJsonValue JSON round-trip in a catch block that returns the original value when serialization fails.

PR surface: Source +4. Total +4 across 1 file.

Reproducibility: yes. —current-main source has an unguarded JSON round trip, and native JSON.stringify deterministically throws for a BigInt or circular value before this helper can return.

Review metrics: none identified.

Stored data model
Persistent data-model change detected: serialized state: extensions/msteams/src/sqlite-state.ts. Confirm migration or upgrade compatibility proof before merge.

Merge readiness
Overall: 🦪 silver shellfish
Proof: 🦪 silver shellfish
Patch quality: 🦪 silver shellfish
Result: blocked until stronger real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Replace the raw-value fallback with a defined JSON-safe conversion or owner-boundary rejection.
  • [P1] Add focused coverage for BigInt and circular input through the MSTeams state path.
  • Post redacted real runtime or persistence proof after the corrected change; updating the PR body should trigger review, or ask a maintainer to comment @clawsweeper re-review if it does not.

Proof guidance:

  • [P1] Needs stronger real behavior proof before merge: The PR body includes helper-level output, but it does not show after-fix behavior through a real MSTeams SQLite-state path; add redacted runtime output or logs that demonstrate the state write/read succeeds. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Risk before merge

  • [P2] Merging this fallback can move the same serialization failure to a later persistence or state-consumer boundary, where it is harder to diagnose and is not covered by the supplied proof.

Maintainer options:

  1. Decide the mitigation before merge
    Keep the persistence conversion JSON-safe: use a defined representation for unsupported values or reject them at the owner boundary, add focused state-path coverage, and show a redacted real MSTeams state round trip after the fix.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Next step before merge

  • [P1] A narrow repair is feasible, but it must establish a JSON-safe persistence contract rather than returning the unserializable input unchanged.

Security
Cleared: The one-file patch does not add dependencies, privileged execution, secret handling, or a concrete security or supply-chain concern.

Review findings

  • [P1] Return a JSON-safe fallback instead of the original value — extensions/msteams/src/sqlite-state.ts:50
Review details

Best possible solution:

Keep the persistence conversion JSON-safe: use a defined representation for unsupported values or reject them at the owner boundary, add focused state-path coverage, and show a redacted real MSTeams state round trip after the fix.

Do we have a high-confidence way to reproduce the issue?

Yes—current-main source has an unguarded JSON round trip, and native JSON.stringify deterministically throws for a BigInt or circular value before this helper can return.

Is this the best way to solve the issue?

No—the proposed fallback suppresses the first exception while retaining the unsupported value; the fix should produce a defined JSON-safe result or fail at the owning state boundary with an actionable error.

Full review comments:

  • [P1] Return a JSON-safe fallback instead of the original value — extensions/msteams/src/sqlite-state.ts:50
    value may be the same BigInt-containing or circular object that made JSON.stringify throw. Returning it makes this helper appear to succeed while passing an invalid value to its SQLite-state consumer, so the serialization failure is deferred rather than fixed. Convert unsupported values to a defined JSON-safe representation (or reject them at the state boundary) and cover the state round trip.
    Confidence: 0.83

Overall correctness: patch is incorrect
Overall confidence: 0.83

AGENTS.md: unclear because the file could not be read completely.

Codex review notes: model internal, reasoning high; reviewed against 756de70e84d1.

Label changes

Label changes:

  • add P2: The PR targets a bounded MSTeams state-conversion crash path, but the proposed repair does not yet reliably preserve the conversion contract.
  • add rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🦪 silver shellfish.
  • add status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The PR body includes helper-level output, but it does not show after-fix behavior through a real MSTeams SQLite-state path; add redacted runtime output or logs that demonstrate the state write/read succeeds. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Label justifications:

  • P2: The PR targets a bounded MSTeams state-conversion crash path, but the proposed repair does not yet reliably preserve the conversion contract.
  • rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🦪 silver shellfish.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The PR body includes helper-level output, but it does not show after-fix behavior through a real MSTeams SQLite-state path; add redacted runtime output or logs that demonstrate the state write/read succeeds. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

PR surface:

Source +4. Total +4 across 1 file.

View PR surface stats
Area Files Added Removed Net
Source 1 6 2 +4
Tests 0 0 0 0
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 1 6 2 +4

Acceptance criteria:

  • [P1] node scripts/run-vitest.mjs extensions/msteams.
  • [P1] git diff --check.

What I checked:

  • Current-main behavior: The base implementation performs an unguarded JSON.stringify followed by JSON.parse, so values such as BigInt and circular structures throw before the conversion completes. (extensions/msteams/src/sqlite-state.ts:46, 756de70e84d1)
  • Patch behavior: The proposed catch returns the original value, including a BigInt or circular object that is still not representable as JSON; this no longer satisfies the conversion function's JSON-value contract. (extensions/msteams/src/sqlite-state.ts:50, 440b24f79b10)
  • PR-provided reproduction: The PR body demonstrates the native JSON.stringify exceptions for both BigInt and circular input, but its after-fix output only invokes the helper and does not prove the value survives the actual MSTeams persisted-state path. (extensions/msteams/src/sqlite-state.ts:46, 440b24f79b10)

Likely related people:

  • pgondhi987: Recent MSTeams extension history makes this a plausible routing contact, but the available review context does not establish ownership of this exact helper. (role: recent adjacent contributor; confidence: low; commits: 9497629; files: extensions/msteams/src/sqlite-state.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

…safe persistence

toPluginJsonValue serializes MSTeams plugin state through
JSON.stringify+parse without guarding against BigInt values or
circular references, which causes a TypeError that tears down the
caller before the state can be persisted.

Add a JSON.stringify replacer that converts BigInt to String so
nested BigInt values (e.g. message IDs) survive the round-trip as
JSON-safe strings. Circular references and other structural failures
fall back to an empty object instead of crashing.

This keeps the persistence conversion contract intact: the return
value is always JSON-safe and can complete the SQLite write-read
round-trip without deferred failures.
@wanyongstar
wanyongstar force-pushed the fix/msteams-guard-toPluginJsonValue branch from 440b24f to 5a5f393 Compare July 22, 2026 02:37
@clawsweeper

clawsweeper Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper status: review started.

I am starting a fresh review of this pull request: fix(msteams): prevent toPluginJsonValue from crashing on unserializable values This is item 1/1 in the current shard. Shard 0/1.

This placeholder means the worker is alive and reading the current context. I will edit this same comment with the actual review when the claws are done clicking.

Crustacean status: shell secured, claws on keyboard, evidence pebbles being sorted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: msteams Channel integration: msteams P2 Normal backlog priority with limited blast radius. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. size: XS status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants