Troubleshooting: Agent Studio graph and custom-tool validation
The Agent Studio canvas (see Build Agents Visually in the Agent Studio Canvas) can reject a publish or a test-run, and the custom-tool registry rejects registration or invocation, each with its own validation code. The runtime-error family (agent runtime errors) covers the codes that fire mid-turn; this page owns the validation family that fires at publish, register, or wiring time, and — in Custom tool runtime failures — the dispatch family that fires later, when a registered executor misbehaves mid-call. Every failure here arrives as a structured envelope — key onerror.code,
and for GRAPH_VALIDATION_FAILED read the per-issue list in
error.details before you touch the canvas:
Graph publish validation
Custom tool registration
These codes come fromPOST /agents/custom-tools and the invoke path
(see Build custom tools for AI agents).
Sample
INVALID_EXECUTOR_URL envelope:
Tool wiring errors
These fire when a graph, registry, or agent reference points at a KB, a handoff target, or a runtime handler that cannot resolve.Custom tool runtime failures
Registration proves your executor URL is reachable and public; dispatch is where production reality shows up. When the agent invokes a registered custom tool (or when you fire the tool’s test endpoint), the platform dispatches a signedPOST to your executor_url and classifies whatever
comes back into one of five codes. Unlike the 422s above, these are not
publish-time gates: they fire per call, against a live executor.
The dispatch contract
- Per-tool dispatch timeout. Every tool carries a
timeout_ms(1,000 to 60,000, default 30,000). One dispatch that overruns it ends the attempt; if the tool configures aretrypolicy, each retry attempt gets its own timeout, and the whole sequence is capped by the agent execution budget. - Response cap. A response body is capped at 1 MiB; a larger body is cut off mid-stream and the attempt fails.
- Who owns what. A
4xxor5xxstatus, a slow response, or a broken TLS chain is your executor’s fault. A dispatch fault that happens before your executor is even reached is the platform’s side. The table below assigns each code to a side.
tools/list handshake timeout and each tools/call is bounded
by the same per-tool timeout_ms (default 30 s). The HTTP custom-tool
surface skips the discovery step, so the per-tool dispatch window is the
only clock.
Decoding the codes
Every dispatch failure result carries
error_code — one of the five
codes — and a sanitized error line that never leaks the raw executor
or network exception. Where the tool configures a retry policy, the
recorded attempt history keeps one entry per attempt with its own
status, duration_ms, and raw error, and the surfaced code is the
terminal outcome after retries.
What to capture
meta.request_idfrom the envelope.- The tool name and the tenant.
duration_msper attempt: neartimeout_mssays slow executor; near-zero says DNS or connection refused; a platform-side error string on a fast attempt says dispatch fault.- The executor’s own status code from the attempt row, and your executor’s logs at the same timestamp.
What NOT to do
- Do not blind-retry
CUSTOM_TOOL_CLIENT_ERROR. A 4xx is your executor deterministically rejecting the request; a loop only burns your retry budget. - Do not loop on
CUSTOM_TOOL_SERVER_ERROReither. A crashing executor keeps crashing; fix the executor first, then retry. - Do not raise
timeout_msto hide a slow executor. The ceiling is 60,000 and the agent execution budget still caps the whole turn; a tool that needs minutes wants the async job-id pattern, not a bigger window. - Do not treat
CUSTOM_TOOL_NETWORK_ERRORas a platform outage. TLS and DNS faults on a public HTTPS URL are executor-side; the platform pins the resolved address for the dispatch exactly as validated at registration.
When to escalate for runtime codes
Escalate onlyCUSTOM_TOOL_DISPATCH_FAILED, the platform-side class,
with the request_id and the attempt rows. Timeout, network, server,
and client classes are executor-side and carry everything you need to
fix them yourself.
KB re-chunking
Decision checklist
Run this after any of the codes above:- Read
error.codeon the envelope. - If it is one of the deterministic 422s (
GRAPH_VALIDATION_FAILED,GRAPH_TOOL_NODES_NOT_SUPPORTED_IN_TEST_RUN,RESERVED_TOOL_NAME,INVALID_EXECUTOR_URL-family reject classes,INVALID_HANDOFF_TARGETS,INVALID_KNOWLEDGE_BASE_IDS) — do NOT retry; fix the payload, the graph, or the registry first. - If it is
TOOL_NAME_TAKENorTOOL_DISABLED— clear the collision or re-enable the tool, then retry. - If it is
TOOL_IMPL_NOT_REGISTERED— treat as a runtime fault; do not retry and escalate. - For
GRAPH_VALIDATION_FAILED, scanerror.detailsfor the exact node/edge and fix on the canvas; the console prints the same list inline. - If it is one of the runtime dispatch codes
(
CUSTOM_TOOL_TIMEOUT,CUSTOM_TOOL_NETWORK_ERROR,CUSTOM_TOOL_SERVER_ERROR,CUSTOM_TOOL_CLIENT_ERROR) — the executor owns the fault; follow Custom tool runtime failures and retry only after the executor changed. - If it is
CUSTOM_TOOL_DISPATCH_FAILED— platform side; a bounded retry is safe, then escalate withrequest_id.
What NOT to do
- Do not retry
GRAPH_VALIDATION_FAILEDin a loop. The graph is invalid; a retry re-runs the same gate. - Do not rename a custom tool to work around
TOOL_NAME_TAKEN. The name is the id the LLM sees and every attached agent trains prompts on it; renaming after the fact breaks trained prompts. Rename the duplicate target instead. - Do not point
executor_urlat an internal host with a public alias. DNS resolution runs at write time and again at dispatch, so a public-looking hostname that resolves internally still fails. - Do not escalate on
TOOL_NAME_TAKEN/TOOL_DISABLED/INVALID_HANDOFF_TARGETS/INVALID_KNOWLEDGE_BASE_IDS/ the 422 validation codes, or on the four executor-owned dispatch codes. These are deterministic tenant-owned gates. Escalate onlyTOOL_IMPL_NOT_REGISTERED(500) andCUSTOM_TOOL_DISPATCH_FAILEDwithrequest_id. - Do not retry the re-chunk on a legacy document. Re-upload through the canonical KB flow first; the 409 is deterministic.
- Do not blind-retry the dispatch family.
CUSTOM_TOOL_CLIENT_ERRORandCUSTOM_TOOL_SERVER_ERRORmean your executor rejected or crashed on the request; onlyCUSTOM_TOOL_DISPATCH_FAILEDis safe to retry as-is.
When to escalate
Escalate to support only forTOOL_IMPL_NOT_REGISTERED (500) and
CUSTOM_TOOL_DISPATCH_FAILED — the platform-side faults. The
request_id from meta lets support trace which registry entry the
executor resolved, or which dispatch attempt faulted. Everything else
on this page is a deterministic tenant-side fix, including all four
executor-owned dispatch codes.
See also
- Build Agents Visually in the Agent Studio Canvas — the canvas that owns the graph validations.
- Build custom tools for AI agents — the registry this page’s codes come from.
- Agent runtime errors — the sibling runbook for mid-turn codes.
- Knowledge base document inspector — the re-chunk action and its version lineage.
- Error code reference — the full catalog this page maps.
- Bring your own MCP servers — the
handshake and
timeout_mscontract the dispatch window mirrors. - Idempotency and safe
retries — the retry-safety
contract
CUSTOM_TOOL_DISPATCH_FAILEDinherits.