Budibase/budibase · error

Multi-object JSON templates must be valid JSON objects

Error message

Multi-object JSON templates must be valid JSON objects

What it means

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.

Source

Thrown at packages/string-templates/src/index.ts:491

    // reopens quote-breaking operator injection for multi-object templates.
    try {
      return documents
        .map(document => {
          const preparedDocument = quoteRawJsonBindings(document)
          const parsed = JSON.parse(
            preparedDocument.template
          ) as JsonTemplateValue
          return processJsonTemplateValue(
            parsed,
            preparedDocument.bindings,
            context,
            opts
          )
        })
        .map(value => JSON.stringify(value))
        .join(" ")
    } catch {
      throw new Error("Multi-object JSON templates must be valid JSON objects")
    }
  }
}

/**
 * Same as function above, but allows logging to be returned - this is only for JS bindings.
 */
export function processStringWithLogsSync(
  string: string,
  context?: object,
  opts?: ProcessOptions
): { result: string; logs: Log[] } {
  if (isBackendService()) {
    throw new Error("Logging disabled for backend bindings")
  }
  return processStringSyncInternal(string, context, {
    ...opts,
    logging: true,

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Quote string bindings and escape/JSON-stringify values before interpolation (use a helper that emits JSON.stringify(value)).
  2. Validate the template by rendering it and running JSON.parse on the result in a test.
  3. Replace object-valued bindings with their string/JSON-serialised equivalents.
  4. Simplify to a single JSON object template, or construct the payload with code instead of string templating.

Example fix

// before
`{ "name": {{user.name}} }` // user.name = O"Brien -> invalid JSON
// after
`{ "name": {{JSONstringify user.name}} }` // binding emitted as "O\"Brien"
Defensive patterns

Strategy: validation

Validate before calling

function jsonSafe(v: unknown): string {
  return JSON.stringify(v) // emits a quoted, escaped JSON token
}
// build the template with jsonSafe bindings, then verify:
const rendered = processJsonStringSync(template, context)
JSON.parse(rendered) // throws early if still invalid

Type guard

function isValidJson(v: string): boolean {
  try { JSON.parse(v); return true } catch { return false }
}

Try / catch

let payload: unknown
try {
  const raw = processJsonStringSync(template, context)
  payload = JSON.parse(raw)
} catch (e) {
  if (e.message.includes("must be valid JSON objects") || e instanceof SyntaxError) {
    payload = { fallback: true }
  } else throw e
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29). Data as JSON: /api/errors/263751ca29653330. Report an issue: GitHub.