Refusals & failure modes
This page is the diagnosis surface for the workflow and run tools: when a call is refused, look the token or code up here. Each entry gives the token verbatim, the tool that raises it, the cause, and the recovery. The normative token tables live in the agent reference; the canonical call sequences live in the cookbook.
Every refusal on this page is fail-closed: Genesis refuses and leaves state intact rather than guessing — nothing partial ever lands.
How to read this page
Refusals arrive in two shapes:
- a status token in the reply —
mission_run_startandmission_run_acceptanswer with a token, and any token other thanStarted/Acceptedmeans the operation did not happen; - an error envelope carrying a
code— the authoring and lifecycle tools refuse withVALIDATION_ERRORorCONFLICT.
A refused call never needs cleanup: fix the cause and retry. For the architecture behind these rules, see the workflows chapter.
Publish & validate failures
Raised by workflow_validate_draft and workflow_publish, code VALIDATION_ERROR. The validator aggregates: it reports every problem in the graph at once, so work through the whole list before you revalidate — there is no hidden queue of problems behind the first one.
| Problem | What the validator saw | Fix |
|---|---|---|
| Gate dominance | A dependency path reaches a write-classified node without passing through a gate. | Add a gate that dominates the write — every path to the write must traverse one. See gates. |
| Ungoverned llm site | A generic llm node is bound to a site that is not a registered deny-all site. | Bind the node to a registered deny-all site. Generic llm nodes carry no tools by construction. |
| Agent toolset out of policy | An agent node's toolset is not a subset of its site's effective tool policy. | Trim the toolset to the site's policy. Any authored tool — write or read — also reclassifies the node as a write at publish (fail-closed; only an empty toolset keeps a node read-classified) — gate dominance then applies to it. |
| Missing stage on a write | The graph is governed and a write node carries no development stage. | Tag the node with one of Design, Implementation, Integration, Verification, PreDeployment. See the publish floor. |
| Legacy node in a new draft | The draft places a node whose lifecycle is Legacy — today exactly one: service:research:llm. Legacy nodes are publish-blocked in new drafts. | Replace it with the current Standard node the catalog offers for the same job. |
| Arm reconvergence | Branch cases, gate decisions or outcome arms converge back onto a shared downstream node. Arms never reconverge. | Keep each arm's continuation separate. An unrouted arm is a valid dead end. |
| Fan-out body shape | A fan-out body breaks its shape rules: a MapFanOut body with more than a single catalog step or sub-workflow reference, or a ForEach Loop Body region carrying structural nodes. | Move a multi-step body into its own workflow and reference it — or, for ForEach only, wire it as a Loop Body region of plain catalog steps. Structural nodes never nest inside a fan-out body. |
| Reserved id segment | A node id uses a reserved segment (__ or #). | Rename the node. |
| Non-waivable control | A waiver was requested on a control that cannot be waived. | There is no path around it — publish with the injected control in place. See waivers. |
Lifecycle conflicts
Code CONFLICT. These protect the three-state lifecycle — Draft → Published → Archived, in that order only.
| Conflict | Raised by | What it means | What to do |
|---|---|---|---|
Editing outside Draft | workflow_update_draft, workflow_delete_draft | The target version is Published or Archived. Only a draft can be edited or deleted. | Create a new draft — published graphs are immutable, so changes always land as a new version. |
| Archiving a non-published version | workflow_archive | Only Published versions archive. A draft is deleted, never archived. | Use workflow_delete_draft on drafts. |
| Archive blocked by live references | workflow_archive | A published workflow still embeds this one as a sub-workflow. | List consumers with workflow_referenced_by, move them with workflow_rebind_flowref (rebinding invalidates gate ratification — they re-approve), then archive. |
Run-start refusals
Raised by mission_run_start. Any token other than Started means no run was created. The full 11-token vocabulary is in the agent reference; the sequence that handles them is attach and run.
| Token | What it means | What to do |
|---|---|---|
RunAlreadyOpen | The mission already has an open run, and runs are strict-sequential by default. | Accept or discard the open run first — or use groupId competition from the start when you want parallel candidates. |
ChildSpawnerDisallowed | The graph contains a node that spawns child missions; such nodes cannot run inside a mission run. | Remove or replace the child-spawning node, republish, then retry. |
FeatureDisabled | Workflows:MissionRuns:StartEnabled is off in this environment. | Ask your operator to enable it; no call parameter works around a disabled flag. |
MissionNotPlanned | The mission has no approved plan yet. | Let planning finish and get the plan approved, then retry. |
MissionTerminal | The mission is finished — completed, failed or cancelled. | Start a new mission, or create one directly with workflow_invoke. |
AgenticMissionUnsupported | This mission's type cannot host workflow runs. | Use a mission that can, or create a fresh one with workflow_invoke. |
TipUnavailable | The mission branch tip could not be resolved right now. | Retry. If it persists, ask your operator. |
WorkflowNotFound | The workflow id and version do not resolve to a known workflow. | Check the id with workflow_list and the version with workflow_get. |
NotInvocable | The version exists but is not runnable — it is a draft, or archived. | Publish first; a run always starts from an explicit published version. |
MaterializationFailed | Building the frozen execution snapshot for this run failed. | Validate the workflow and its parameter bindings, then retry. If it persists, ask your operator. |
Accept refusals
Raised by mission_run_accept. Any token other than Accepted means nothing merged: no changement was created and the mission tip did not move. The full vocabulary is in the agent reference.
| Token | What it means | What to do |
|---|---|---|
StaleRefused | The mission tip moved after this run started; its base is stale. | Start a fresh run off the new tip. Never try to force a stale accept. |
MergeConflict | The run branch no longer merges cleanly onto the mission tip. | Start a fresh run from the current tip and let it propose the change again. |
GroupAlreadyWon | Another run in the same competition group was already accepted. Losing runs are rejected and their branches deleted. | Nothing to recover — the group has its winner. Start a new run if you still need the change. |
NotProposed | The run is not in Proposed — it is still executing, or was already accepted or discarded. | Poll mission_run_get until it reaches Proposed, resolving any waiting gates with decision_respond. |
TipUnavailable | The mission branch tip could not be resolved right now. | Retry. If it persists, ask your operator. |
The last token deserves its own entry, because it comes from the acceptance doctrine rather than from run state:
ValidationRefused— Acceptance is physical: before a run merges, Genesis validates the run branch by exercising it — never by an LLM verdict. The check is fail-closed: if no validation backend is reachable in your environment, the accept is refused rather than waved through. The run stays intact asProposed; nothing merges. Recovery: confirm a validation backend is available (ask your operator), then retry the accept.
Revert refuses on conflict
Raised by mission_revert. A revert unwinds changements in reverse order, cascading over dependents. It is fail-closed on conflict: if any changement in the cascade cannot be reverted cleanly, the whole cascade aborts and the refusal names the failing member. Nothing partial lands — the mission branch is exactly as it was before the call.
Recovery:
- Run
mission_revert_previewfirst — it shows the full dependent cascade before you commit to anything. - Inspect the named changement in the stack (
mission_changement_stack) and resolve what makes it conflict. - Retry. A refused revert changed nothing, so retrying is always safe.
See the changement stack for how changements compose on the mission branch.