{"record":{"id":"b71ac94b3408d0ad","repo":"clockworklabs/SpacetimeDB","slug":"invalid-json-failed-to-parse-string","errorCode":null,"errorMessage":"Invalid JSON: failed to parse string","messagePattern":"Invalid JSON: failed to parse string","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"crates/bindings-typescript/src/server/runtime.ts","lineNumber":110,"sourceCode":"\nfunction responseIntoWire(response: SyncResponse): [HttpResponse, Uint8Array] {\n  return [\n    {\n      headers: serializeHeaders(response.headers),\n      version: response.version,\n      code: response.status,\n    },\n    response.bytes(),\n  ];\n}\n\nexport function parseJsonObject(json: string): JsonObject {\n  let value: unknown;\n\n  try {\n    value = JSON.parse(json);\n  } catch {\n    throw new Error('Invalid JSON: failed to parse string');\n  }\n\n  if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n    throw new Error('Expected a JSON object at the top level');\n  }\n\n  // The runtime check above guarantees this cast is safe\n  return value as JsonObject;\n}\n\nclass JwtClaimsImpl implements JwtClaims {\n  readonly fullPayload: JsonObject;\n  private readonly _identity: Identity;\n  /**\n   * Creates a new JwtClaims instance.\n   * @param rawPayload The JWT payload as a raw JSON string.\n   * @param identity The identity for this JWT. We are only taking this because we don't have a blake3 implementation (which we need to compute it).\n   */","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/524b4487d949b61a07d4f39c862d1290259dfd20/crates/bindings-typescript/src/server/runtime.ts#L92-L128","documentation":"parseJsonObject runs JSON.parse and converts any throw into 'Invalid JSON: failed to parse string'. In the module runtime it parses the JWT payload of an authenticated request (JwtClaimsImpl, runtime.ts:133) and is exported for handlers parsing request bodies. Any syntactically invalid JSON (trailing commas, single quotes, raw newlines, truncation, an HTML error page) triggers it.","triggerScenarios":"A request JWT whose payload base64url segment does not decode to valid JSON; an HTTP handler calling parseJsonObject on a request body that is not strict JSON; a body truncated or replaced by a proxy's HTML error page.","commonSituations":"Clients sending form-encoded or loosely quoted JSON with Content-Type: application/json; hand-crafted test tokens; upstream gateways returning an HTML 502 page where JSON was expected.","solutions":["Wrap the parse in try/catch and return a 400 with a clear message instead of letting the module throw","Log or curl the exact raw bytes being parsed to spot truncation, BOMs, or wrong encoding","If the input is a JWT, use a real three-part token from your identity provider rather than a placeholder string"],"exampleFix":"// before\nconst claims = parseJsonObject(bodyText); // throws on bad input\n\n// after\nlet claims;\ntry {\n  claims = parseJsonObject(bodyText);\n} catch {\n  return new Response(JSON.stringify({ error: 'invalid JSON body' }), { status: 400 });\n}","handlingStrategy":"try-catch","validationCode":"function tryParseJson(text: string): { ok: true; value: unknown } | { ok: false } {\n  try {\n    return { ok: true, value: JSON.parse(text) };\n  } catch {\n    return { ok: false };\n  }\n}\nconst parsed = tryParseJson(bodyText);\nif (!parsed.ok) return new Response('invalid JSON', { status: 400 });","typeGuard":null,"tryCatchPattern":"catch (e) { if (e instanceof Error && e.message === 'Invalid JSON: failed to parse string') return 400; throw e; }","preventionTips":["Never feed untrusted request bodies or token payloads to parseJsonObject without a try/catch","Validate Content-Type and reject non-JSON payloads at the handler boundary","Log raw payloads (length + first bytes) when debugging to catch truncation and HTML error pages"],"tags":["json","parsing","jwt","typescript"],"backgroundTag":"invalid-json","analyzedSha":"524b4487d949b61a07d4f39c862d1290259dfd20","analyzedAt":"2026-08-16T23:58:54.611Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}