Skip to content

fix(webapp): strip null bytes from idempotency and debounce keys at trigger - #4527

Merged
ericallam merged 1 commit into
mainfrom
feature/tri-13030-fix-null-byte-in-trigger-input-fails-taskruncreate-with-an
Aug 7, 2026
Merged

fix(webapp): strip null bytes from idempotency and debounce keys at trigger#4527
ericallam merged 1 commit into
mainfrom
feature/tri-13030-fix-null-byte-in-trigger-input-fails-taskruncreate-with-an

Conversation

@ericallam

Copy link
Copy Markdown
Member

What

A trigger request carrying a Unicode NUL (U+0000) in the idempotency key or debounce key reached prisma.taskRun.create() and failed the insert, so the caller got an opaque 500 and the run was never created.

These two keys are stored in jsonb columns (idempotencyKeyOptions, debounce), and Postgres rejects a NUL inside a jsonb value with SQLSTATE 22P05 ("unsupported Unicode escape sequence ... cannot be converted to text"). This fix strips the NUL from both keys at the single trigger-input chokepoint (#buildEngineTriggerInput), which every trigger path flows through (single, batch item, mollified, and drainer replay).

Stripping matches the existing precedent for run errors and task events. It does not change dedup behaviour: the idempotency dedup identity is the hashed key (a clean 64-char digest), computed independently of the raw key we clean, so dedup keeps working exactly as before. For debounce the key is used directly, so the cleaned key also becomes the grouping key, an acceptable change for input that is already malformed.

Why not payload / metadata / tags

Those are text columns fed by JSON.stringify, which escapes a NUL to a safe escape sequence, so they do not hit this failure on the normal JSON path. (A raw NUL in a text column throws a different code, 22021, and is not what triggers this issue.) The observed failures are the jsonb 22P05 variant, which is only reachable via the two key fields.

Evidence

Red then green (containerTest, real Postgres): with the fix reverted, triggering through the real service with a NUL in idempotencyKeyOptions.key / debounce.key fails with the exact 22P05 signature; with the fix, the run is created and the stored key has the NUL removed.

Full-stack e2e (isolated stack, real HTTP): POST /api/v1/tasks/:taskId/trigger with a NUL inside idempotencyKeyOptions.key ("acme<NUL>inc") and, separately, debounce.key ("grp<NUL>1"):

  • both returned HTTP 200 with a created run (previously 500)
  • stored idempotencyKeyOptions = { "key": "acmeinc", "scope": "run" } (7 chars, NUL removed)
  • stored debounce.key = "grp1" (4 chars, NUL removed)
  • both runs render in the dashboard

Unit tests cover the helper (strip, no-op fast path, object-reference reuse, null/undefined pass-through).

Rollout / rollback

Server-only webapp change, no flag. Zero behaviour change for clean input; only affects inputs that previously 500'd. Rollback is a straight revert, no data migration.

Known limitation

A raw NUL in a plain-string idempotency key (not created via idempotencyKeys.create()) lands in a text column and throws 22021 instead. That variant is not addressed here because stripping it would change the dedup identity, so it warrants a separate decision. Not observed in practice.

refs TRI-13030

…rigger

A caller-supplied Unicode NUL (U+0000) in the idempotency key or debounce
key reached prisma.taskRun.create() and failed the insert with a Postgres
22P05 (jsonb) error, so the trigger returned an opaque 500 and the run was
never created. Strip the NUL from these keys at the single trigger-input
chokepoint. The idempotency dedup identity is the hashed key and is
unaffected.
@changeset-bot

changeset-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: c352827

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Added utilities that remove NUL characters from strings and key-bearing objects. Applied the utilities to idempotency and debounce options during engine trigger input construction. Added unit tests and container-backed integration tests for sanitization and persistence behavior. Added a webapp change note documenting the change.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely describes the main change: stripping null bytes from idempotency and debounce keys at trigger time.
Description check ✅ Passed The description clearly explains the issue, implementation, testing evidence, rollout, rollback, and known limitation, despite not following every template heading.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/tri-13030-fix-null-byte-in-trigger-input-fails-taskruncreate-with-an

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

coderabbitai[bot]

This comment was marked as resolved.

@ericallam
ericallam marked this pull request as ready for review August 7, 2026 11:08

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

Open in Devin Review

Comment thread apps/webapp/app/runEngine/services/triggerTask.server.ts
@ericallam
ericallam merged commit 7246f67 into main Aug 7, 2026
47 checks passed
@ericallam
ericallam deleted the feature/tri-13030-fix-null-byte-in-trigger-input-fails-taskruncreate-with-an branch August 7, 2026 12:28
@github-actions github-actions Bot mentioned this pull request Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants