Skip to content

fix(core): parse run metadata returned as a JSON string - #5052

Open
princejain756 wants to merge 2 commits into
triggerdotdev:mainfrom
princejain756:fix-run-metadata-string
Open

princejain756 wants to merge 2 commits into
triggerdotdev:mainfrom
princejain756:fix-run-metadata-string

Conversation

@princejain756

Copy link
Copy Markdown

metadata.refresh() inside a task always rejects with Expected object, received string at "metadata".

The GET route at /api/v1/runs/:runId/metadata returns the stored metadata as a serialized JSON string (with metadataType: "application/json"), while UpdateMetadataResponseBody expects a record, so client-side validation rejects every response. runs.retrieve() and the PUT handler both return a parsed object, which is why only this path breaks.

The schema now parses a string payload before validating, so refresh() works against servers returning either shape. Object responses and rejection of non-JSON values are unchanged.

I checked whether the server route should instead deserialize before responding, but the client still has to tolerate deployed servers and self-hosted installs on older versions, so the lenient parse belongs here regardless.

Fixes #5039

GET /api/v1/runs/:runId/metadata returns the stored metadata string
unparsed, while the response schema expects a record, so
metadata.refresh() always failed validation. Accept a string payload
and JSON.parse it before validating, keeping object responses and the
rejection of non-JSON values unchanged.

Fixes triggerdotdev#5039
@changeset-bot

changeset-bot Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 6ba06cd

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 30 packages
Name Type
@trigger.dev/core Patch
@trigger.dev/build Patch
trigger.dev Patch
@trigger.dev/linear Patch
@trigger.dev/python Patch
@trigger.dev/redis-worker Patch
@trigger.dev/schema-to-json Patch
@trigger.dev/slack Patch
@trigger.dev/sdk Patch
@internal/clickhouse Patch
@internal/llm-model-catalog Patch
@internal/metrics-pipeline Patch
@trigger.dev/rbac Patch
@internal/redis Patch
@internal/replication Patch
@internal/run-engine Patch
@internal/run-store Patch
@internal/schedule-engine Patch
@internal/tracing Patch
@internal/webhook-engine Patch
@internal/webhook-sources Patch
@internal/dashboard-agent Patch
@internal/cache Patch
@trigger.dev/react-hooks Patch
@trigger.dev/rsc Patch
@trigger.dev/billing Patch
@trigger.dev/database Patch
@trigger.dev/otlp-importer Patch
@trigger.dev/sso Patch
@internal/testcontainers Patch

Not sure what this means? Click here to learn what changesets are.

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

@coderabbitai

coderabbitai Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 0a613357-717f-46da-a658-d1fbd90070b4
📥 Commits

Reviewing files that changed from the base of the PR and between 4120811 and 6ba06cd.

📒 Files selected for processing: 1
  • .changeset/run-metadata-json-string.md
🚧 Files skipped from review as they are similar to previous changes: 1
  • .changeset/run-metadata-json-string.md

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 8 remain after this review.

Walkthrough

UpdateMetadataResponseBody.metadata now attempts to parse string values as JSON before record validation. If parsing fails, the original string proceeds to validation. Non-string values pass through unchanged. Tests cover object metadata, valid JSON-string metadata, and rejection of invalid JSON strings. A patch changeset records the change.

Priority: ➖ Normal

Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to 6ba06

The patch changeset is correctly formed. No identified issue prevents merging after normal checks.

Pre-merge checks: Passed 5
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: parsing run metadata returned as a JSON string.
Description check Passed The description explains the failure, the response-shape difference, the schema change, and the reason for client-side parsing. It also references issue #5039. It does not include the template’s check…
Linked Issues check Passed Issue #5039 requires metadata.refresh() to accept the serialized JSON metadata returned by the endpoint. The supplied change summary says UpdateMetadataResponseBody.metadata parses string input be…
Out of Scope Changes check Passed The supplied change summary lists a schema change, focused tests, and a changeset. Each change supports Issue #5039. The unavailable diff did not provide additional evidence, but the supplied whole-PR…
Docstring Coverage Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 2…
Full details: Description check

Explanation

The description explains the failure, the response-shape difference, the schema change, and the reason for client-side parsing. It also references issue #5039. It does not include the template’s checklist, testing steps, or separate changelog and screenshots sections.

Full details: Linked Issues check

Explanation

Issue #5039 requires metadata.refresh() to accept the serialized JSON metadata returned by the endpoint. The supplied change summary says UpdateMetadataResponseBody.metadata parses string input before record validation and leaves non-string values unchanged. The tests cover object input, valid JSON-string input, and rejection of invalid JSON strings. This meets the coding requirement.

Full details: Out of Scope Changes check

Explanation

The supplied change summary lists a schema change, focused tests, and a changeset. Each change supports Issue #5039. The unavailable diff did not provide additional evidence, but the supplied whole-PR summary identifies no unrelated changes.

Full details: Docstring Coverage

Explanation

No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 2 files. (1 skipped: 1 unsupported.)

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

devin-ai-integration[bot]

This comment was marked as resolved.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: b0283923-8a20-4dd1-9395-6e978c75593a
📥 Commits

Reviewing files that changed from the base of the PR and between 8491915 and 4120811.

📒 Files selected for processing: 3
  • .changeset/run-metadata-json-string.md
  • packages/core/src/v3/schemas/api.ts
  • packages/core/src/v3/schemas/runMetadata.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

📜 Review details
⚠️ CI failures not shown inline: 2

GitHub Actions: Vouch - Check PR / 1_check-vouch.txt: fix(core): parse run metadata returned as a JSON string

Conclusion: failure

View job details

##[group]Run hustcer/setup-nu@920172d92eb04671776f3ba69d605d3b09351c30
 with:
   version: *
   features: default
   check-latest: false
   enable-plugins: false
   github-***REDACTED_SECRET_ASSIGNMENT***
 env:
   GH_***REDACTED_SECRET_ASSIGNMENT***
 ##[endgroup]
 versionSpec: *
 coerce version: *
 Try to get assets for Nu: arch = x64, platform = linux, feature = default
 ##[error]No release for Nushell matching version specifier * of default feature.

GitHub Actions: Vouch - Check PR / check-vouch: fix(core): parse run metadata returned as a JSON string

Conclusion: failure

View job details

##[group]Run hustcer/setup-nu@920172d92eb04671776f3ba69d605d3b09351c30
 with:
   version: *
   features: default
   check-latest: false
   enable-plugins: false
   github-***REDACTED_SECRET_ASSIGNMENT***
 env:
   GH_***REDACTED_SECRET_ASSIGNMENT***
 ##[endgroup]
 versionSpec: *
 coerce version: *
 Try to get assets for Nu: arch = x64, platform = linux, feature = default
 ##[error]No release for Nushell matching version specifier * of default feature.
🧰 Additional context used
📚 Code guidelines: 4
packages/core/AGENTS.md — auto-discovered
.claude/rules/sdk-packages.md — auto-discovered
AGENTS.md — auto-discovered
.github/copilot-instructions.md — auto-discovered
📓 Path-based instructions: 4
**NEVER import the root** (`@trigger.dev/core`).

📄 CodeRabbit inference engine (packages/core/AGENTS.md)

Files:

  • packages/core/src/v3/schemas/api.ts
  • packages/core/src/v3/schemas/runMetadata.test.ts
Source excerpt: Changes to `packages/` are **customer-facing**.

📄 CodeRabbit inference engine (.claude/rules/sdk-packages.md)

Files:

  • packages/core/src/v3/schemas/api.ts
  • packages/core/src/v3/schemas/runMetadata.test.ts
Source excerpt: **packages/core** (`@trigger.dev/core`): Shared types.

📄 CodeRabbit inference engine (AGENTS.md)

Files:

  • packages/core/src/v3/schemas/api.ts
  • packages/core/src/v3/schemas/runMetadata.test.ts
Source excerpt: This is the repo for Trigger.dev, a background jobs platform written in TypeScript.

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Files:

  • packages/core/src/v3/schemas/api.ts
  • packages/core/src/v3/schemas/runMetadata.test.ts
🔇 Additional comments: 2
packages/core/src/v3/schemas/api.ts: 1

1772-1785: LGTM!

packages/core/src/v3/schemas/runMetadata.test.ts: 1

1-32: LGTM!

@@ -0,0 +1,4 @@
"@trigger.dev/core": patch

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Add the opening changeset fence.

Line 1 starts with the package bump, but Changesets requires --- before the bump and after it. This file has only the closing fence. Changesets cannot read it as a valid patch changeset, which can block release commands. Add --- above Line 1. (github.com)

As per coding guidelines, “Changes to packages/ are customer-facing. Always add a changeset: pnpm run changeset:add.”

Proposed fix
--- "a/.changeset/run-metadata-json-string.md"
+++ "b/.changeset/run-metadata-json-string.md"
@@ -1,4 +1,5 @@
+---
 "@trigger.dev/core": patch
 ---
 
 `metadata.refresh()` now works against deployments where `GET /api/v1/runs/:runId/metadata` returns the run metadata as a JSON string rather than an object. The response schema parses a string payload before validating, so `refresh()` resolves with the same metadata record on every version.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"@trigger.dev/core": patch
---
"@trigger.dev/core": patch

Source: Coding guidelines

This branch has not been deployed

No deployments
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.

metadata.refresh() always fails: "Expected object, received string at metadata" (GET /api/v1/runs/{id}/metadata returns serialized metadata)

1 participant