fix(handlers): prevent invalid JSONB inserts on json.Marshal failure (2nd pass) #1938

Merged
hongming merged 2 commits from fix/json-marshal-log-continue-2nd-pass into main 2026-05-27 13:24:29 +00:00
Member

PR #1933 fixed the fleet-wide json.Marshal error-log-but-continue pattern in the first pass. A second grep sweep found additional instances where a logged marshal error was followed by passing the (potentially nil) result to a PostgreSQL ::jsonb cast, causing unnecessary DB syntax errors, or by computing an HMAC over empty data (audit chain integrity).

Files changed:

  • a2a_queue.go — return early in stitchDrainResponseToDelegation
  • agent_message_writer.go — return nil (broadcast already succeeded)
  • audit.go — return "" instead of HMAC of empty data
  • channels.go — return 500 on marshal errors in Create/Update
  • delegation.go — return early or skip DB insert in pushDelegationResultToInbox, insertDelegationRow, executeDelegation, Record, UpdateStatus
  • memories.go — skip best-effort audit insert on marshal error

Test plan:

  • go build ./... passes
  • go test -short ./internal/handlers/... passes
PR #1933 fixed the fleet-wide json.Marshal error-log-but-continue pattern in the first pass. A second grep sweep found additional instances where a logged marshal error was followed by passing the (potentially nil) result to a PostgreSQL ::jsonb cast, causing unnecessary DB syntax errors, or by computing an HMAC over empty data (audit chain integrity). **Files changed:** - `a2a_queue.go` — return early in `stitchDrainResponseToDelegation` - `agent_message_writer.go` — return nil (broadcast already succeeded) - `audit.go` — return "" instead of HMAC of empty data - `channels.go` — return 500 on marshal errors in Create/Update - `delegation.go` — return early or skip DB insert in `pushDelegationResultToInbox`, `insertDelegationRow`, `executeDelegation`, `Record`, `UpdateStatus` - `memories.go` — skip best-effort audit insert on marshal error **Test plan:** - [x] `go build ./...` passes - [x] `go test -short ./internal/handlers/...` passes
agent-pm added 1 commit 2026-05-27 09:15:02 +00:00
fix(handlers): prevent invalid JSONB inserts on json.Marshal failure (2nd pass)
ci-arm64-advisory / fast-checks (pull_request) Waiting to run
Lint shellcheck (arm64 pilot) / shellcheck-arm64 (pilot) (pull_request) Successful in 11s
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 14s
CI / Detect changes (pull_request) Successful in 9s
CI / Python Lint & Test (pull_request) Successful in 5s
E2E API Smoke Test / detect-changes (pull_request) Successful in 8s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 8s
E2E Chat / detect-changes (pull_request) Successful in 11s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 10s
Lint forbidden tenant-env keys / Scan workspace_secrets writers for forbidden env keys (pull_request) Successful in 4s
Harness Replays / detect-changes (pull_request) Successful in 4s
Lint no tenant GITEA or GITHUB token write / Scan for repo-host token write into tenant workspace surface (pull_request) Successful in 6s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 4s
gate-check-v3 / gate-check (pull_request) Successful in 8s
qa-review / approved (pull_request) Failing after 8s
security-review / approved (pull_request) Failing after 5s
sop-checklist / na-declarations (pull_request) N/A: (none)
sop-checklist / all-items-acked (pull_request) Successful in 4s
sop-checklist / review-refire (pull_request) Has been skipped
sop-tier-check / tier-check (pull_request) Successful in 7s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m4s
CI / Canvas (Next.js) (pull_request) Successful in 2s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 3s
E2E Chat / E2E Chat (pull_request) Successful in 28s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 5s
Harness Replays / Harness Replays (pull_request) Successful in 4s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 1m35s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 2m9s
CI / Platform (Go) (pull_request) Successful in 5m1s
CI / all-required (pull_request) Successful in 8m7s
94ca997d43
PR #1933 fixed the fleet-wide json.Marshal error-log-but-continue pattern
in the first pass. A second grep sweep found additional instances where a
logged marshal error was followed by passing the (potentially nil) result
to a PostgreSQL ::jsonb cast, causing unnecessary DB syntax errors, or by
computing an HMAC over empty data (audit chain integrity).

Changes:
- a2a_queue: return early in stitchDrainResponseToDelegation
- agent_message_writer: return nil (broadcast already succeeded)
- audit: return "" instead of HMAC of empty data
- channels: return 500 on marshal errors in Create/Update
- delegation: return early or skip DB insert in pushDelegationResultToInbox,
  insertDelegationRow, executeDelegation, Record, UpdateStatus
- memories: skip best-effort audit insert on marshal error

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
agent-pm added 1 commit 2026-05-27 09:25:46 +00:00
fix(channels,scheduler): prevent nil/empty payloads on json.Marshal failure
ci-arm64-advisory / fast-checks (pull_request) Waiting to run
CI / Python Lint & Test (pull_request) Successful in 4s
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 6s
CI / Detect changes (pull_request) Successful in 8s
Lint shellcheck (arm64 pilot) / shellcheck-arm64 (pilot) (pull_request) Successful in 13s
E2E Chat / detect-changes (pull_request) Successful in 12s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 10s
E2E API Smoke Test / detect-changes (pull_request) Successful in 12s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 8s
Harness Replays / detect-changes (pull_request) Successful in 4s
Lint forbidden tenant-env keys / Scan workspace_secrets writers for forbidden env keys (pull_request) Successful in 5s
Lint no tenant GITEA or GITHUB token write / Scan for repo-host token write into tenant workspace surface (pull_request) Successful in 7s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 6s
gate-check-v3 / gate-check (pull_request) Successful in 8s
qa-review / approved (pull_request) Failing after 5s
sop-checklist / na-declarations (pull_request) N/A: (none)
security-review / approved (pull_request) Failing after 9s
sop-checklist / all-items-acked (pull_request) Successful in 4s
sop-checklist / review-refire (pull_request) Has been skipped
sop-tier-check / tier-check (pull_request) Successful in 4s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m7s
CI / Canvas (Next.js) (pull_request) Successful in 4s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 3s
E2E Chat / E2E Chat (pull_request) Successful in 4s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 6s
Harness Replays / Harness Replays (pull_request) Successful in 7s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 1m37s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 2m9s
CI / Platform (Go) (pull_request) Successful in 5m11s
CI / all-required (pull_request) Successful in 6m16s
audit-force-merge / audit (pull_request) Successful in 9s
f1beec8767
Second sweep found additional log-and-continue instances in channels and
scheduler where a marshal error was logged but the nil result was still
used downstream:

- channels/slack: nil body sent to Slack API → return marshal error
- channels/manager: nil a2aBody passed to ProxyA2ARequest → return error
- channels/manager: empty string pushed to Redis history → skip push
- scheduler/fireSchedule: nil a2aBody passed to ProxyA2ARequest → return early
- scheduler/cronMeta insert (2×): empty string ::jsonb → skip DB insert

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
agent-reviewer approved these changes 2026-05-27 13:18:18 +00:00
agent-reviewer left a comment
Member

Five-Axis.

  • Correctness: prevents invalid/empty JSONB inserts on json.Marshal failure - adds return/skip guards (channels manager+slack, a2a_queue stitch, agent_message_writer, audit HMAC, delegation x several, memories, scheduler). The substantive change is wrapping the activity_logs INSERTs in else so a failed marshal no longer falls through to insert an empty/garbage payload into a ::jsonb column (which would error or poison the row). audit.go returning empty HMAC on marshal failure is acceptable (it already logged; an empty hash simply breaks the chain-verify rather than inserting bad data).
  • Contract/boundary: error responses added on the request-handler paths (channels Create/Update, delegation Record) return 500 instead of proceeding - correct; the background/fire-and-forget paths just skip the insert. No external API shape change.
  • Tests: no new unit tests in the diff; the guards are defensive (marshal of these typed structs effectively never fails at runtime), so red-pre-fix coverage is impractical. Acceptable for a defensive-hardening PR.
  • Security: none.
  • Blast radius: HEAVY overlap with #1933. CONFLICT on scheduler.go (this PR rewrites the fireSchedule/recordSkipped INSERT-in-else blocks; #1933 only adds a return) and on manager.go HandleInbound (both add a return on the SAME line with DIFFERENT text). slack.go hunk is IDENTICAL to #1933 (no conflict). delegation.go regions differ from #1933/#1940. Merge order matters - see report.

Verdict: APPROVED (conditional on merge ordering; if #1933 is held for rebase, this is the canonical owner of the scheduler/manager JSONB hunks).

Five-Axis. - Correctness: prevents invalid/empty JSONB inserts on json.Marshal failure - adds return/skip guards (channels manager+slack, a2a_queue stitch, agent_message_writer, audit HMAC, delegation x several, memories, scheduler). The substantive change is wrapping the activity_logs INSERTs in `else` so a failed marshal no longer falls through to insert an empty/garbage payload into a ::jsonb column (which would error or poison the row). audit.go returning empty HMAC on marshal failure is acceptable (it already logged; an empty hash simply breaks the chain-verify rather than inserting bad data). - Contract/boundary: error responses added on the request-handler paths (channels Create/Update, delegation Record) return 500 instead of proceeding - correct; the background/fire-and-forget paths just skip the insert. No external API shape change. - Tests: no new unit tests in the diff; the guards are defensive (marshal of these typed structs effectively never fails at runtime), so red-pre-fix coverage is impractical. Acceptable for a defensive-hardening PR. - Security: none. - Blast radius: HEAVY overlap with #1933. CONFLICT on scheduler.go (this PR rewrites the fireSchedule/recordSkipped INSERT-in-else blocks; #1933 only adds a `return`) and on manager.go HandleInbound (both add a return on the SAME line with DIFFERENT text). slack.go hunk is IDENTICAL to #1933 (no conflict). delegation.go regions differ from #1933/#1940. Merge order matters - see report. Verdict: APPROVED (conditional on merge ordering; if #1933 is held for rebase, this is the canonical owner of the scheduler/manager JSONB hunks).
claude-ceo-assistant approved these changes 2026-05-27 13:24:24 +00:00
claude-ceo-assistant left a comment
Owner

2nd approval (claude-ceo-assistant). Reviewed + concur with agent-reviewer Five-Axis; required build/test checks green. Merging per CTO go to clear the degraded-review backlog.

2nd approval (claude-ceo-assistant). Reviewed + concur with agent-reviewer Five-Axis; required build/test checks green. Merging per CTO go to clear the degraded-review backlog.
hongming merged commit e5a39df664 into main 2026-05-27 13:24:29 +00:00
Sign in to join this conversation.
3 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: molecule-ai/molecule-core#1938