T-06Tool Errors as Observations

/tools/tool-errors

A failed tool call becomes a result the model can read — what went wrong and what to try instead — rather than an exception that ends the run.

Step-by-step walkthrough2 variants · 11 steps

Error as exception

  1. Twenty steps in, the model calls a tool with a value the API rejects.
  2. The tool raises. Nothing between it and the loop was written to catch that.
  3. The exception unwinds the harness — twenty steps of work gone, over a value the model could have fixed in one.
  4. The usual patch: catch it and hand back a status code. Better, but opaque.
  5. The model can’t tell what to change, so it sends the identical call again, and again.

Error as observation

  1. Twenty steps in, the model calls a tool with a value the API rejects.
  2. The tool raises — inside a wrapper that never lets an exception reach the loop.
  3. The failure becomes a tool result, flagged as an error, that says what was wrong and what is allowed.
  4. The model reads it like any other observation.
  5. Transient failures are different: the harness retries those itself, with an idempotency key so a retried write lands once.
  6. The model fixes the argument on its next call. One step lost, not the run.
Key insight

The model is the best error handler in the loop, but only for errors it can see. Bad arguments and refused actions go back as instructive results; transient failures are retried by the harness, with idempotency keys so a retried write lands once.

Failure mode

Opaque errors. “Error 400” says that something failed but not what to change, so the model resends the identical arguments and learns nothing from the attempt.

Further reading

Elsewhere in the atlas