Budibase/budibase · error · Error

Unable to split value of type ${typeof value}: ${value}

Error message

Unable to split value of type ${typeof value}: ${value}

What it means

stringSplit converts a loop's iterable string into an array by splitting on newlines or commas. It accepts arrays and strings only; any other value type (number, object, null handled earlier, boolean) causes an Error stating the received type and value.

Source

Thrown at packages/server/src/automations/automationUtils.ts:336

      .replace(/loop/, substitute)
    substitutedHbsString += before + block
    pointer = closedPointer
  }
  if (checkForJS) {
    substitutedHbsString = encodeJSBinding(substitutedHbsString)
  }
  return substitutedHbsString
}

export function stringSplit(value: string | string[]) {
  if (value == null) {
    return []
  }
  if (Array.isArray(value)) {
    return value
  }
  if (typeof value !== "string") {
    throw new Error(`Unable to split value of type ${typeof value}: ${value}`)
  }
  const splitOnNewLine = value.split("\n")
  if (splitOnNewLine.length > 1) {
    return splitOnNewLine
  }
  return value.split(",")
}

export function matchesLoopFailureCondition(
  step: LoopV2Step,
  currentItem: any
) {
  const { failure } = step.inputs
  if (!failure) {
    return false
  }

  if (isPlainObject(currentItem)) {

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Wrap the value as a string in the binding (e.g. use string conversion in the loop iterable) or select a string column.
  2. Point the loop at an array output (e.g. query rows array) instead of a scalar.
  3. Change the source column/field type to text, or use a script step to shape the data before the loop.
  4. Inspect the trigger/step outputs to confirm the iterable's runtime type.

Example fix

// before
iterations: {{trigger.count}}  // number
// after
iterations: "{{trigger.count}}"  // string, or pass an array
Defensive patterns

Strategy: type-guard

Validate before calling

const iterable = loop.iterable
if (typeof iterable !== "string" && !Array.isArray(iterable)) {
  throw new Error(`Loop iterable must be string or array, got ${typeof iterable}`)
}

Type guard

const isSplittable = (v: unknown): v is string | unknown[] =>
  typeof v === "string" || Array.isArray(v)

Try / catch

try {
  outputs = await runLoopStep(loopInputs)
} catch (e) {
  if (/Unable to split value of type/.test(e.message)) {
    // coerce the binding to string or select an array output
  } else throw e
}

Prevention

When it happens

Trigger: A loop step's iterable binding resolves to a number, object, or boolean instead of a string or array — e.g. iterating a numeric field or an object from a query output.

Common situations: Binding to a table column of number type; a REST query returning an object instead of a list; binding resolution producing a single non-string primitive.

Understand the failure class

Background: "Wrong argument type", "must be a string", "expected Array or Prism::Scope": TypeError and ArgumentError when a library receives a value of the wrong type — this error's family across 28 libraries.

Related errors


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