coleam00/Archon · warning

${label} must be a JSON-encoded object

Error message

${label} must be a JSON-encoded object

What it means

The run-workflow route decodes multipart 'tiers' and 'aliases' fields via decodeObjectField; each must be absent or a JSON-encoded object string. If the field is present but is not a string (e.g. an uploaded File or an array of parts from { all: true }), the route returns 400 with '<label> must be a JSON-encoded object' before even attempting JSON.parse.

Source

Thrown at packages/server/src/routes/api.ts:3440

        }
        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 },
            'run_workflow.model_overrides_parse_failed'
          );
          return { ok: false, error: `${label} must be a JSON-encoded object` };
        }
      };
      const decodedTiers = decodeObjectField(body.tiers, 'tiers');
      if (!decodedTiers.ok) return apiError(c, 400, decodedTiers.error);
      const decodedAliases = decodeObjectField(body.aliases, 'aliases');
      if (!decodedAliases.ok) return apiError(c, 400, decodedAliases.error);
      const parsedOverrides = parseRunModelOverridesFields(
        decodedTiers.value,

View on GitHub (pinned to 0773b97458)

Solutions

  1. Send tiers/aliases as plain text fields containing JSON: -F 'tiers={"default":2}'.
  2. Send each field exactly once — no duplicate parts.
  3. Do not attach these fields as files; the route accepts strings only.
  4. If you have them in files, read and inline the contents as the field value.

Example fix

// before
-F 'tiers=@tiers.json'   // arrives as a File part
// after
-F "tiers=$(cat tiers.json)"   // arrives as a string part
Defensive patterns

Strategy: validation

Validate before calling

function appendJsonField(form: FormData, label: 'tiers' | 'aliases', value: Record<string, unknown>): void {
  form.append(label, JSON.stringify(value)); // plain string part, not a file, appended once
}
// pre-send check:
const raw = form.get('tiers');
if (raw !== null && (typeof raw !== 'string' || !isValidJsonObject(raw))) throw new Error('tiers must be a JSON-encoded object string');

Type guard

function isJsonEncodedObject(s: unknown): s is string {
  if (typeof s !== 'string') return false;
  try {
    const v: unknown = JSON.parse(s);
    return typeof v === 'object' && v !== null && !Array.isArray(v);
  } catch { return false; }
}

Try / catch

try {
  const res = await runWorkflow(form);
  if (res.status === 400 && (await res.json()).error.includes('must be a JSON-encoded object')) {
    throw new Error('tiers/aliases must be plain text fields containing a JSON object — not file uploads, not duplicates');
  }
} catch (err) { /* rebuild form fields as strings */ }

Prevention

When it happens

Trigger: Sending tiers or aliases as a file part (name="tiers"; filename=...) instead of a plain text form field, or duplicating the field so parseBody({ all: true }) yields an array, or sending a non-string part type.

Common situations: Uploading a tiers.json file via -F 'tiers=@tiers.json' instead of -F 'tiers=<json>'; accidentally appending the same field twice; generic form builders that attach files for object payloads.

Related errors


AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01). Data as JSON: /api/errors/cbb8eafa1d91d3dc. Report an issue: GitHub.