{"record":{"id":"263751ca29653330","repo":"Budibase/budibase","slug":"multi-object-json-templates-must-be-valid-json-obj","errorCode":null,"errorMessage":"Multi-object JSON templates must be valid JSON objects","messagePattern":"Multi-object JSON templates must be valid JSON objects","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/string-templates/src/index.ts","lineNumber":491,"sourceCode":"    // reopens quote-breaking operator injection for multi-object templates.\n    try {\n      return documents\n        .map(document => {\n          const preparedDocument = quoteRawJsonBindings(document)\n          const parsed = JSON.parse(\n            preparedDocument.template\n          ) as JsonTemplateValue\n          return processJsonTemplateValue(\n            parsed,\n            preparedDocument.bindings,\n            context,\n            opts\n          )\n        })\n        .map(value => JSON.stringify(value))\n        .join(\" \")\n    } catch {\n      throw new Error(\"Multi-object JSON templates must be valid JSON objects\")\n    }\n  }\n}\n\n/**\n * Same as function above, but allows logging to be returned - this is only for JS bindings.\n */\nexport function processStringWithLogsSync(\n  string: string,\n  context?: object,\n  opts?: ProcessOptions\n): { result: string; logs: Log[] } {\n  if (isBackendService()) {\n    throw new Error(\"Logging disabled for backend bindings\")\n  }\n  return processStringSyncInternal(string, context, {\n    ...opts,\n    logging: true,","sourceCodeStart":473,"sourceCodeEnd":509,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/string-templates/src/index.ts#L473-L509","documentation":"processJsonStringSync in packages/string-templates/src/index.ts renders a template that must produce a valid JSON object. When interpolation of the (multi-object) JSON template fails and the parsed result cannot be assembled as a JSON object, it throws \"Multi-object JSON templates must be valid JSON objects\". The template's output is expected to be parseable JSON after bindings are substituted.","triggerScenarios":"Using a JSON template whose bindings inject values that break JSON syntax: raw strings containing unescaped quotes, multiline strings, values that are objects/arrays rather than scalars, or bindings producing nothing where a required token is expected.","commonSituations":"Building request bodies for REST/API steps where a context binding contains user text with quotes; passing objects (instead of strings/scalars) into {{ }} placeholders inside JSON templates; templates edited by hand with trailing commas or missing quotes around string bindings.","solutions":["Quote string bindings and escape/JSON-stringify values before interpolation (use a helper that emits JSON.stringify(value)).","Validate the template by rendering it and running JSON.parse on the result in a test.","Replace object-valued bindings with their string/JSON-serialised equivalents.","Simplify to a single JSON object template, or construct the payload with code instead of string templating."],"exampleFix":"// before\n`{ \"name\": {{user.name}} }` // user.name = O\"Brien -> invalid JSON\n// after\n`{ \"name\": {{JSONstringify user.name}} }` // binding emitted as \"O\\\"Brien\"","handlingStrategy":"validation","validationCode":"function jsonSafe(v: unknown): string {\n  return JSON.stringify(v) // emits a quoted, escaped JSON token\n}\n// build the template with jsonSafe bindings, then verify:\nconst rendered = processJsonStringSync(template, context)\nJSON.parse(rendered) // throws early if still invalid","typeGuard":"function isValidJson(v: string): boolean {\n  try { JSON.parse(v); return true } catch { return false }\n}","tryCatchPattern":"let payload: unknown\ntry {\n  const raw = processJsonStringSync(template, context)\n  payload = JSON.parse(raw)\n} catch (e) {\n  if (e.message.includes(\"must be valid JSON objects\") || e instanceof SyntaxError) {\n    payload = { fallback: true }\n  } else throw e\n}","preventionTips":["Always JSON-stringify bindings that contain user text before interpolation","Keep string bindings inside quotes in the JSON template","Test-render templates with adversarial inputs (quotes, newlines) and JSON.parse the result","Construct JSON payloads programmatically instead of string templating where possible"],"tags":["json","handlebars","validation","template"],"backgroundTag":"invalid-json-template","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}