You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
metadata.refresh() always fails: "Expected object, received string at metadata" (GET /api/v1/runs/{id}/metadata returns serialized metadata) #5039
returns metadata as a serialized JSON string, alongside metadataType: "application/json". In contrast, GET /api/v3/runs/<runId> (runs.retrieve()) returns metadata as an object.
Where it seems to come from
Server: the GET loader in apps/webapp/app/routes/api.v1.runs.$runId.metadata.ts, added in 89431c7, returns the stored metadata value as-is, without deserializing it. The PUT handler in the same file returns a parsed object.
Client:getRunMetadata (packages/core/src/v3/apiClient/index.ts) validates the response with UpdateMetadataResponseBody, which expects metadata to be a record.
Workaround
Read the metadata back with runs.retrieve(runId) instead of metadata.refresh().
The GET loader in apps/webapp/app/routes/api.v1.runs.$runId.metadata.ts returns the stored packet string as-is at all three read points (replica, mollifier buffer, primary), while runs.retrieve deserializes through parsePacketAsJson (ApiRetrieveRunPresenter.server.ts) and the PUT handler in the same file returns the parsed object. So the SDK's UpdateMetadataResponseBody (metadata: z.record(...)) always rejects the GET response.
Suggested fix, verified locally: deserialize in the loader with parsePacketAsJson({ data, dataType: metadataType ?? "application/json" }) at the three return points, return {} when metadata is absent (matching the PUT service's empty case in updateMetadata.server.ts), and pass through a buffered snapshot that already holds an object. I added route tests for the PG / buffered / object-passthrough / empty cases and updated the existing replica-lag guard test for the parsed shape: 13/13 pass with the fix, and the new tests fail against the unpatched route.
Happy to open a PR with it if a maintainer is willing to vouch (CONTRIBUTING gates PRs on that).
Activity
lakshya-dhariwal commentedon Oct 19, 2026
Confirmed the root cause and have a tested fix.
The GET loader in
apps/webapp/app/routes/api.v1.runs.$runId.metadata.tsreturns the stored packet string as-is at all three read points (replica, mollifier buffer, primary), whileruns.retrievedeserializes throughparsePacketAsJson(ApiRetrieveRunPresenter.server.ts) and the PUT handler in the same file returns the parsed object. So the SDK'sUpdateMetadataResponseBody(metadata: z.record(...)) always rejects the GET response.Suggested fix, verified locally: deserialize in the loader with
parsePacketAsJson({ data, dataType: metadataType ?? "application/json" })at the three return points, return{}when metadata is absent (matching the PUT service's empty case inupdateMetadata.server.ts), and pass through a buffered snapshot that already holds an object. I added route tests for the PG / buffered / object-passthrough / empty cases and updated the existing replica-lag guard test for the parsed shape: 13/13 pass with the fix, and the new tests fail against the unpatched route.Happy to open a PR with it if a maintainer is willing to vouch (CONTRIBUTING gates PRs on that).