Skip to main content

Failure Taxonomy

Failures should be structured. A product should not collapse every failed run into "the agent failed."

The taxonomy is used by Planflow events, Quality Lab results, logs, and trace learning records. The goal is to make the next action obvious: improve search metadata, repair a contract, ask for user input, configure auth, retry the downstream API, or reject a learning suggestion.

Mental Model

A tool-call workflow fails at a stage, for a reason, with evidence. Keep those three fields separate.

FieldMeaningExample
stageWhere the failure happenedsynthesize, auth_preflight, execute
reasonStable machine-readable reason codeunsatisfied_field, auth_context_required
evidenceCompact proof used for debuggingmissing field, selected target, HTTP status

Do not use the exception message as the contract. Messages can change; reason codes should remain stable.

Failure Lifecycle

StageTypical Reason CodesUsually Fixed By
retrieveno_candidates, not_retrieved, low_confidencesemantic metadata, aliases, OpenAPI summaries, graph edges
select_targetllm_target_mismatch, llm_target_not_in_candidates, ambiguous_target, selector_mismatchtarget selector evidence, result shape, contract fit, LLM catalog prompt
synthesizeunknown_target, unsatisfied_field, enum_required, dynamic_option_required, cycle, max_depth, user_input_fallbackIO contracts, producer edges, context defaults, user input UX
bind_requestbinding_failed, argument_coercion_failed, missing_required_argumentschema contract, field mapping, runtime argument builder
auth_preflightauth_context_required, auth_profile_missing, auth_header_resolution_failedcollection auth profile, product session, session header resolver
executeauth_failed, http_4xx, http_5xx, timeout, network_errordownstream API, request construction, credentials, retry policy
cleanupcleanup_failed, cleanup_not_configuredQuality Lab mutation case owner
learnscrub_failed, promotion_rejected, insufficient_repeated_successtrace scrubbing, promotion policy, human review
serviceuncaught_server_erroradapter or service bug

The engine only owns product-neutral stages. Product adapters may add transport or UI-specific stages, but they should preserve stage, reason, and compact evidence.

Engine Synthesis Errors

PathSynthesizer raises PlanSynthesisError and subclasses for synthesis failures. Adapters should call to_dict() instead of parsing exception strings.

from graph_tool_call.plan import PathSynthesizer, PlanSynthesisError

synthesizer = PathSynthesizer(graph_artifact)

try:
plan = synthesizer.synthesize(
target="getOrderDetail",
goal="show me the order detail",
entities={},
)
except PlanSynthesisError as exc:
diagnostic = exc.to_dict()
# {"stage": "synthesize", "reason": "unsatisfied_field", ...}

to_dict() returns a stable envelope:

{
"stage": "synthesize",
"reason": "unsatisfied_field",
"message": "required field cannot be supplied",
"field_name": "orderNo",
"semantic_tag": "order_id",
"target_tool": "getOrderDetail"
}

The exact detail keys depend on the reason. Treat extra fields as additive.

Reason Code Catalog

Search and Selection

ReasonMeaningEvidence To StoreCommon Action
no_candidatesRetrieval returned no usable toolsquery, filters, top_kinspect catalog build and index coverage
not_retrievedExpected target was absent from Top-Kexpected target, returned tool namesimprove semantic metadata or aliases
low_confidenceCandidate scores are too weakscore distribution, thresholdwiden Top-K or add evidence
llm_target_mismatchLLM chose a target different from the expected targetLLM target, expected target, selected targetinspect target selector diagnostics
llm_target_not_in_candidatesLLM chose a tool outside the retrieved catalogLLM target, candidate namespass selector-ranked catalog to the LLM
ambiguous_targetMultiple tools had similar evidencemargin, tied candidatesask for clarification or preserve LLM target
selector_mismatchDeterministic selector selected the wrong targetrank signals, override flagtune generic selector policy or metadata

Plan Synthesis

ReasonMeaningEvidence To StoreCommon Action
unknown_targetTarget tool is not in the graph artifacttarget tool, graph versionrebuild artifact or repair target selection
unsatisfied_fieldRequired consume field cannot be filledfield name, semantic tag, target tooladd producer edge, context default, or user slot
enum_requiredRequired enum field has no selected valuefield name, enum values if safemap enum labels or ask user
dynamic_option_requiredA producer can fetch runtime options for a missing fieldproducer name, options path, label hintsshow option picker before final plan
cycleTool dependency chain revisits a toolchain, tool nameinspect graph edges and producer ranking
max_depthDependency search exceeded synthesizer depthmax depth, current toolreduce graph noise or increase depth deliberately
user_input_fallbackPlanner continued by asking the user for a valuefield name, required flagadd UX slot or context default

Auth and Execution

ReasonAPI Called?MeaningCommon Action
auth_context_requirednoAuth is required but no runtime user/session context existsrun from logged-in UI or service account
auth_profile_missingnoCollection/tool requires auth but has no auth profileconfigure collection auth profile
auth_header_resolution_failednoProfile exists but adapter could not build headersinspect session header resolver
auth_failedyesDownstream API returned 401 or 403refresh credentials or inspect downstream policy
http_4xxyesDownstream API rejected the requestinspect request arguments and business validation
http_5xxyesDownstream API failed server-sideretry only if safe; inspect API logs
timeoutmaybeRequest exceeded timeoutinspect timeout, pagination, downstream latency
network_errormaybeTransport failed before a useful HTTP responseinspect DNS, TLS, proxy, or allowlist

Quality Lab and Learning

ReasonMeaningCommon Action
cleanup_failedMutating validation case did not restore statefix cleanup step before enabling the case
cleanup_not_configuredMutating execute case has no cleanup plankeep case disabled or add cleanup
scrub_failedTrace payload could not be safely compactedreject learning record
insufficient_repeated_successSuggestion has not met promotion thresholdkeep in shadow mode
promotion_rejectedHuman or policy rejected a suggestionstore rejection reason, do not apply boost

Normalized Failure Record

Adapters should normalize failures into a compact record before writing Quality Lab results, logs, or learning attempts.

{
"stage": "synthesize",
"reason": "unsatisfied_field",
"message": "Required field orderNo cannot be supplied",
"tool": "getOrderDetail",
"plan_id": "plan_01HZ...",
"step_id": null,
"retryable": false,
"operator_action": "ask_user_or_add_context_default",
"evidence": {
"field_name": "orderNo",
"semantic_tag": "order_id",
"target_tool": "getOrderDetail"
}
}

Use retryable carefully. Auth header refresh, network errors, and 5xx responses may be retryable. Missing user input, missing auth profile, and unsupported contracts usually are not retryable without a product action.

Runner Event Example

Runner events are transport-neutral data. XGEN-style adapters often forward dataclasses.asdict(event) to SSE, logs, and Quality Lab results.

{
"type": "step.failed",
"stage": "execute",
"plan_id": "plan_01HZ...",
"step_id": "step_2",
"tool": "getOrderDetail",
"graph_tool_call_version": "0.32.1",
"trace_metadata": {
"failure_reason": "http_4xx",
"http_status": 400,
"auth_readiness": {
"required": true,
"auth_profile_id_present": true,
"session_station_header_names": ["Authorization"],
"failure_reason": null
}
}
}

The event may contain additional fields. Consumers should read only the fields they understand and preserve unknown metadata when forwarding.

Security Boundary

Failure records must never store raw credentials or personal data. Persist only booleans, header names, field paths, statuses, and scrubbed values.

Do StoreDo Not Store
xgen_auth_token_present: truebearer token value
session_station_header_names: ["Authorization"]Authorization: Bearer ...
field_name: "orderNo"raw order response body
http_status: 403cookie or API key
session_id_hashraw user id, email, phone number

This boundary is important because failure records are later used as trace learning input.

Triage Guide

SymptomCheck FirstLikely Fix
Expected tool is not in Top-Kretrieval evidence and semantic metadataimprove aliases, summaries, contracts, or graph edges
Expected tool is in Top-K but not selectedtarget_selector.rank_signals and LLM targetimprove action/resource/shape evidence or selector policy
Plan asks for an obvious fieldapi_contract.consumes, producer edges, context defaultsadd context default, field mapping, or producer
Execute is blocked before API callauth_readiness.failure_reasonconfigure auth profile or session header resolution
API returns 401/403downstream request header names and auth profile freshnessrefresh auth or inspect downstream policy
API returns 400rendered request argumentsfix schema binding, enum mapping, or user input
Write case succeeds but leaves datacleanup resultadd cleanup assertion before allowing mutation
Failure turns into repeated success laterlearning attempts and suggestionskeep suggestion shadowed until promotion gate passes

Quality Lab Assertions

Quality Lab should assert failure reasons, not just pass/fail booleans.

{
"mode": "execute",
"query": "show order detail",
"expected_target": "getOrderDetail",
"assertions": {
"selected_target": "getOrderDetail",
"allowed_failure_reasons": [
"auth_context_required",
"auth_failed",
"http_4xx"
],
"uncaught_server_error": false
}
}

This makes incomplete environments useful. A dev collection without credentials can still prove that search and plan work, while execution fails with a known auth reason instead of a server error.

Validation

Use failure taxonomy assertions in runner, plan, auth, and Quality Lab tests:

poetry run pytest tests/ -q -k "failure or quality_lab or runner or auth"

For documentation-only changes, also run:

cd website
npm run typecheck
npm run build