ZhuLinsen/daily_stock_analysis · error · CodexAppServerError

capability_unsupported

capability_unsupported

Error message

No cancellation-safe DSA tools are available to Codex

What it means

Raised by CodexAgentBackend right before spawning a Codex App Server thread when ToolSurface.list_tools('public', cancellation_safe_only=True) returns an empty list. The Codex integration only exposes tools whose ToolPolicy.cancellation_safe flag is True, because a user cancellation must be able to interrupt the turn safely. If the registry is empty or every registered tool is marked cancellation-unsafe, the backend refuses to start the session with code 'capability_unsupported'.

Source

Thrown at src/agent/codex_agent_backend.py:152

                command,
                tool_surface=self.tool_surface,
                tool_context=tool_context,
                request_timeout=remaining_timeout(),
                tool_event_callback=on_tool_event,
                deadline=deadline,
                cancel_event=request.cancel_event,
                max_tool_calls=request.max_steps,
            ) as client:
                client.request_timeout = remaining_timeout()
                tool_names = [
                    item["name"]
                    for item in self.tool_surface.list_tools(
                        "public",
                        cancellation_safe_only=True,
                    )
                ]
                if not tool_names:
                    raise CodexAppServerError(
                        "capability_unsupported",
                        "No cancellation-safe DSA tools are available to Codex",
                    )
                developer_instructions = request.system_prompt
                if request.stock_scope is None:
                    developer_instructions = (
                        f"{developer_instructions}\n\n{_NO_STOCK_SCOPE_INSTRUCTION}"
                    )
                thread_id = client.start_thread(
                    tool_names=tool_names,
                    base_instructions=_BASE_INSTRUCTIONS,
                    developer_instructions=developer_instructions,
                )
                client.request_timeout = remaining_timeout()
                isolation = client.inspect_external_tool_isolation(thread_id)
                if not isolation.get("passed"):
                    raise CodexAppServerError(
                        "capability_unsupported",

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Register at least one tool whose ToolPolicy sets cancellation_safe=True before invoking the Codex backend
  2. Inspect the registry at startup: assert tool_surface.list_tools('public', cancellation_safe_only=True) is non-empty and fail fast with a clear provisioning error
  3. If you constructed ToolSurface.empty(), replace it with ToolSurface(registry) built from your real ToolRegistry
  4. Audit recent changes to tool policy definitions to see whether cancellation_safe was inadvertently flipped to False

Example fix

// before
surface = ToolSurface.empty()  # protocol-only, no tools registered
backend = CodexAgentBackend(tool_surface=surface)
await backend.run(request)  # raises capability_unsupported

// after
registry = build_default_registry()  # registers DSA tools
surface = ToolSurface(registry)
if not surface.list_tools('public', cancellation_safe_only=True):
    raise RuntimeError('no cancellation-safe tools registered; check tool policies')
backend = CodexAgentBackend(tool_surface=surface)
Defensive patterns

Strategy: validation

Validate before calling

safe = surface.list_tools("public", cancellation_safe_only=True)
if not safe:
    raise ProvisioningError(
        "no cancellation-safe tools registered; register tools with "
        "ToolPolicy(cancellation_safe=True) before starting the Codex backend"
    )
backend = CodexAgentBackend(tool_surface=surface)

Type guard

def has_cancellation_safe_tools(surface: ToolSurface) -> bool:
    return bool(surface.list_tools("public", cancellation_safe_only=True))

Try / catch

try:
    await backend.run(request)
except CodexAppServerError as exc:
    if exc.code == "capability_unsupported":
        fail_fast("tool provisioning defect: " + str(exc))
    raise

Prevention

When it happens

Trigger: Calling the Codex agent backend when the ToolRegistry contains no tools, or when every ToolDefinition has policy.cancellation_safe=False; also triggered when ToolSurface.empty() (the Phase 6a protocol-only surface backed by an empty ToolRegistry) is wired into a production backend instead of a populated registry.

Common situations: A new deployment forgets to run tool registration at startup; a refactor removes the only cancellation-safe tool; a test harness uses ToolSurface.empty() outside preflight tests; policy defaults were changed so tools default to cancellation_safe=False.

Related errors


AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15). Data as JSON: /api/errors/edd5d3012904b05e. Report an issue: GitHub.