coleam00/Archon · error · Error
Workflow run has invalid model_bindings metadata.
Error message
Workflow run has invalid model_bindings metadata.
What it means
The engine failed to parse the `model_bindings` metadata persisted on a workflow run, or found a forbidden shape: overrides keyed by `tiers` or `aliases` are not valid at the run level, and `effective` bindings must never appear in run metadata (they are computed). This guard protects resumed runs from silently running with different models than the workflow intended.
Source
Thrown at packages/workflows/src/model-validation.ts:512
const value = metadata?.[RUN_MODEL_BINDINGS_METADATA_KEY];
if (value === undefined) return undefined;
const parsed = runModelBindingsMetadataSchema.safeParse(value);
if (!parsed.success) {
const path = parsed.error.issues[0]?.path ?? [];
const bindingName = typeof path[2] === 'string' ? path[2] : 'unknown';
if (path.includes('thinking')) {
throw new Error(`Model binding '${bindingName}' has invalid thinking options.`);
}
if (path.includes('effort')) {
throw new Error(`Model binding '${bindingName}' has an invalid effort.`);
}
if (path[0] === 'overrides' && (path[1] === 'tiers' || path[1] === 'aliases')) {
throw new Error(`Workflow run has invalid model_bindings ${path[1]} metadata.`);
}
if (path[0] === 'effective') {
throw new Error('Workflow run has invalid effective model bindings.');
}
throw new Error('Workflow run has invalid model_bindings metadata.');
}
const tiers = Object.fromEntries(
Object.entries(parsed.data.overrides.tiers ?? {}).map(([name, preset]) => [
name,
normalizePersistedOverridePreset(name, preset),
])
);
const aliases = Object.fromEntries(
Object.entries(parsed.data.overrides.aliases ?? {}).map(([name, preset]) => [
name,
normalizePersistedOverridePreset(name, preset),
])
);
for (const [name, preset] of Object.entries(parsed.data.effective.aliases)) {
assertValidPersistedPreset(name, preset);
}
View on GitHub (pinned to 0773b97458)
Solutions
- Remove `overrides.tiers`, `overrides.aliases`, and `effective` keys from the run's `model_bindings` metadata (only per-node overrides belong there), or delete and re-run the workflow so metadata is regenerated.
- Check which binary version wrote the run; resume with the same version that created it.
- Set model tiers/aliases through supported config (.archon/config.yaml tiers.*, `archon ai tier set`) instead of injecting run metadata.
- If the run row is unrecoverable, start a fresh run; the workflow definition remains the source of truth.
Example fix
// before (hand-edited run metadata)
{"model_bindings": {"overrides": {"tiers": {"small": "haiku"}}}}
// after
{"model_bindings": {"overrides": {"nodes": {"review": "haiku"}}}} Defensive patterns
Strategy: validation
Validate before calling
function isSafeRunBindings(meta: unknown): boolean {
const m = meta as { model_bindings?: { overrides?: Record<string, unknown>; effective?: unknown } } | null;
const o = m?.model_bindings?.overrides;
return !m?.model_bindings?.effective
&& (!o || !('tiers' in o) && !('aliases' in o));
} Type guard
function hasValidBindings(m: unknown): m is { model_bindings?: { overrides?: Record<string, never> } } {
return typeof m === 'object' && m !== null && isSafeRunBindings(m);
} Try / catch
try {
const bindings = readRunModelBindingsMetadata(run);
startRun(run.id, bindings);
} catch (err) {
if ((err as Error).message.includes('invalid model_bindings')) {
log.warn('Discarding corrupt run metadata; restarting run fresh', { runId: run.id });
startFreshRun(run.workflowId);
} else throw err;
} Prevention
- Never hand-edit run rows' metadata columns; use CLI/config to change model settings.
- Resume runs with the same binary version that created them.
- Do not persist computed `effective` bindings into run metadata.
- Keep schema-shape changes to run metadata behind additive, versioned writers.
When it happens
Trigger: A run row (or rehydrated event payload) carries `model_bindings.overrides.tiers`, `model_bindings.overrides.aliases`, or `model_bindings.effective`, or the metadata blob otherwise fails the persistence schema in readRunModelBindingsMetadata during executeWorkflow/resume.
Common situations: Hand-editing the SQLite/Postgres runs table; resuming a run persisted by an older or newer binary that wrote a different metadata shape; a tool that copies 'effective' bindings back into run metadata; a bug in a custom migration.
Related errors
- unreadableGateMessage(run, attention, approval) — one of: "R
- Cannot execute run '${detachedPreCreatedRun.id}': it belongs
- Dry-run failed; missing stubs: ${blockingMissingStubs.join('
- Cannot resume container run '${resumable?.id ?? '?'}': its i
- Failed to update conversation: ${err.message}
AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01).
Data as JSON: /api/errors/94bf0b5bae1b8a40.
Report an issue: GitHub.