{"record":{"id":"94379da319fc8fa4","repo":"coleam00/Archon","slug":"inputs-must-be-a-json-encoded-object-of-string-val","errorCode":null,"errorMessage":"inputs must be a JSON-encoded object of string values","messagePattern":"inputs must be a JSON-encoded object of string values","errorType":"http","errorClass":null,"httpStatus":400,"severity":"warning","filePath":"packages/server/src/routes/api.ts","lineNumber":3429,"sourceCode":"      if (body.configPath !== undefined) {\n        return apiError(c, 400, 'configPath is not supported; send validated config content');\n      }\n\n      // Declared inputs (#2554). A form field can only be a string, so the map travels\n      // JSON-encoded. A malformed field is refused rather than ignored — silently\n      // dropping it would start the run without the values the caller thought it sent.\n      const rawInputs = body.inputs;\n      if (rawInputs !== undefined) {\n        if (typeof rawInputs !== 'string') {\n          return apiError(c, 400, 'inputs must be a JSON-encoded object of string values');\n        }\n        let decoded: unknown;\n        try {\n          decoded = JSON.parse(rawInputs);\n        } catch (parseErr: unknown) {\n          getLog().warn({ err: parseErr, workflowName }, 'run_workflow.inputs_parse_failed');\n          return apiError(c, 400, 'inputs must be a JSON-encoded object of string values');\n        }\n        const parsed = parseRunInputsField(decoded);\n        if (!parsed.ok) return apiError(c, 400, parsed.error);\n        workflowInputs = parsed.inputs;\n      }\n\n      const decodeObjectField = (\n        raw: string | File | (string | File)[] | undefined,\n        label: 'tiers' | 'aliases'\n      ): { ok: true; value?: unknown } | { ok: false; error: string } => {\n        if (raw === undefined) return { ok: true };\n        if (typeof raw !== 'string') {\n          return { ok: false, error: `${label} must be a JSON-encoded object` };\n        }\n        try {\n          return { ok: true, value: JSON.parse(raw) as unknown };\n        } catch (parseErr: unknown) {\n          getLog().warn(\n            { err: parseErr, workflowName, field: label },","sourceCodeStart":3411,"sourceCodeEnd":3447,"githubUrl":"https://github.com/coleam00/Archon/blob/0773b9745896ef0612e709c80845a0f7db315b19/packages/server/src/routes/api.ts#L3411-L3447","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\n-F 'inputs={branch: main}'            // not JSON\n// after\n-F 'inputs={\"branch\":\"main\"}'        // JSON-encoded object of string values","handlingStrategy":"validation","validationCode":"function encodeInputs(inputs: Record<string, string>): string {\n  for (const [k, v] of Object.entries(inputs)) {\n    if (typeof v !== 'string') throw new Error(`inputs.${k} must be a string value`);\n  }\n  return JSON.stringify(inputs); // JSON object of string values only\n}\nform.append('inputs', encodeInputs({ branch: 'main', count: '3' }));","typeGuard":"function isStringRecord(v: unknown): v is Record<string, string> {\n  return typeof v === 'object' && v !== null && !Array.isArray(v)\n    && Object.values(v).every(x => typeof x === 'string');\n}\n// pre-send: isStringRecord(JSON.parse(encodedInputs))","tryCatchPattern":"try {\n  const res = await runWorkflow(form);\n  if (res.status === 400 && (await res.json()).error.includes('inputs must be a JSON-encoded object')) {\n    throw new Error('inputs field must be JSON like {\"k\":\"v\"} — string values only');\n  }\n} catch (err) { /* fix encoding, retry */ }","preventionTips":["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."],"tags":["http-400","json","workflow","input-validation"],"backgroundTag":"invalid-json-field","analyzedSha":"0773b9745896ef0612e709c80845a0f7db315b19","analyzedAt":"2026-09-01T02:28:07.064Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}