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
- Wrap the value as a string in the binding (e.g. use string conversion in the loop iterable) or select a string column.
- Point the loop at an array output (e.g. query rows array) instead of a scalar.
- Change the source column/field type to text, or use a script step to shape the data before the loop.
- 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
- Bind loops to array outputs (query rows, table rows) whenever possible.
- Convert numeric/scalar bindings to strings explicitly.
- Check trigger output types in the builder before using them as iterables.
- Use a script step to normalize data shapes before loops.
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
- Automation ID is required to test a saved password
- No trigger found for automation
- IMAP password is required when connection details change
- Attachments must have both "url" and "filename" keys. You ha
- Email trigger inputs are required
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/f8a69e7bf316823e.
Report an issue: GitHub.