coleam00/Archon · warning
inputs must be a JSON-encoded object of string values
Error message
inputs must be a JSON-encoded object of string values
What it means
On the run-workflow route, the multipart 'inputs' field must be a JSON-encoded object of string values. When JSON.parse(rawInputs) throws (or parseRunInputsField rejects), the server logs run_workflow.inputs_parse_failed and returns 400 with this message, telling the caller their inputs field is not the expected JSON object string.
Source
Thrown at packages/server/src/routes/api.ts:3429
if (body.configPath !== undefined) {
return apiError(c, 400, 'configPath is not supported; send validated config content');
}
// Declared inputs (#2554). A form field can only be a string, so the map travels
// JSON-encoded. A malformed field is refused rather than ignored — silently
// dropping it would start the run without the values the caller thought it sent.
const rawInputs = body.inputs;
if (rawInputs !== undefined) {
if (typeof rawInputs !== 'string') {
return apiError(c, 400, 'inputs must be a JSON-encoded object of string values');
}
let decoded: unknown;
try {
decoded = JSON.parse(rawInputs);
} catch (parseErr: unknown) {
getLog().warn({ err: parseErr, workflowName }, 'run_workflow.inputs_parse_failed');
return apiError(c, 400, 'inputs must be a JSON-encoded object of string values');
}
const parsed = parseRunInputsField(decoded);
if (!parsed.ok) return apiError(c, 400, parsed.error);
workflowInputs = parsed.inputs;
}
const decodeObjectField = (
raw: string | File | (string | File)[] | undefined,
label: 'tiers' | 'aliases'
): { ok: true; value?: unknown } | { ok: false; error: string } => {
if (raw === undefined) return { ok: true };
if (typeof raw !== 'string') {
return { ok: false, error: `${label} must be a JSON-encoded object` };
}
try {
return { ok: true, value: JSON.parse(raw) as unknown };
} catch (parseErr: unknown) {
getLog().warn(
{ err: parseErr, workflowName, field: label },View on GitHub (pinned to 0773b97458)
Solutions
- Send inputs as a JSON-encoded object with only string values: '{"branch":"main","count":"3"}'.
- Validate locally: JSON.parse(rawInputs) succeeds and every Object.values entry is typeof 'string'.
- Watch shell quoting — single-quote the JSON in bash so double quotes survive.
- Use the JSON-body variant of the route if your client struggles with form encoding.
Example fix
// before
-F 'inputs={branch: main}' // not JSON
// after
-F 'inputs={"branch":"main"}' // JSON-encoded object of string values Defensive patterns
Strategy: validation
Validate before calling
function encodeInputs(inputs: Record<string, string>): string {
for (const [k, v] of Object.entries(inputs)) {
if (typeof v !== 'string') throw new Error(`inputs.${k} must be a string value`);
}
return JSON.stringify(inputs); // JSON object of string values only
}
form.append('inputs', encodeInputs({ branch: 'main', count: '3' })); Type guard
function isStringRecord(v: unknown): v is Record<string, string> {
return typeof v === 'object' && v !== null && !Array.isArray(v)
&& Object.values(v).every(x => typeof x === 'string');
}
// pre-send: isStringRecord(JSON.parse(encodedInputs)) Try / catch
try {
const res = await runWorkflow(form);
if (res.status === 400 && (await res.json()).error.includes('inputs must be a JSON-encoded object')) {
throw new Error('inputs field must be JSON like {"k":"v"} — string values only');
}
} catch (err) { /* fix encoding, retry */ } Prevention
- Serialize inputs with JSON.stringify; never pass YAML or key=value text.
- Coerce all values to strings before encoding (numbers, booleans included).
- Single-quote JSON in shell so double quotes survive to the server.
- Round-trip the encoded field through JSON.parse locally as a pre-send check.
When it happens
Trigger: Sending an 'inputs' form field whose value is not valid JSON (e.g. k=v, single-quoted pseudo-JSON, or a bare string), or valid JSON that is not an object of string values (arrays, nested objects, numbers/booleans as values).
Common situations: CLI/scripts shell-quoting JSON so quotes are stripped or mangled; passing YAML or key=value pairs instead of JSON; forgetting that form fields are strings and sending nested objects.
Related errors
- ${label} must be a JSON-encoded object
- config must be a JSON-encoded object
- Invalid JSON in request body
- ❌ **Composed fan-out failed** (node `${node.id}`): ${current
- Cannot execute run '${detachedPreCreatedRun.id}': it belongs
AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01).
Data as JSON: /api/errors/94379da319fc8fa4.
Report an issue: GitHub.