Errors
This content is for the 0.1 version. Switch to the latest version for up-to-date documentation.
Five exception types, all sealed under AhpException. The distinction they draw
is the one that matters operationally: whether retrying could possibly help.
sealed class AhpException implements Exception { final String message;}The types
Section titled “The types”| Type | Raised when | Retry? |
|---|---|---|
AhpRpcException |
The host answered with a JSON-RPC error | Depends on code |
AhpTimeoutException |
A request got no answer in time | Yes |
AhpTransportException |
The socket failed to open or dropped | Yes, with backoff |
AhpClosedException |
A request was made on a closed connection | No — reconnect first |
AhpDecodeException |
A payload did not match the schema | No — a bug, somewhere |
Matching is exhaustive:
switch (error) { case AhpRpcException(:final code, :final data): case AhpTimeoutException(): case AhpTransportException(:final cause): case AhpClosedException(): case AhpDecodeException(:final type, :final field):}Protocol codes
Section titled “Protocol codes”if (e.code == AhpErrorCodes.unsupportedProtocolVersion) { /* ... */ }| Code | Constant |
|---|---|
-32001 |
sessionNotFound |
-32002 |
providerNotFound |
-32003 |
sessionAlreadyExists |
-32004 |
turnInProgress |
-32005 |
unsupportedProtocolVersion |
-32006 |
contentNotFound |
-32007 |
authRequired |
-32008 |
notFound |
-32009 |
permissionDenied |
-32010 |
alreadyExists |
-32011 |
conflict |
The standard JSON-RPC codes live in JsonRpcErrorCodes.
Errors carrying data
Section titled “Errors carrying data”Some codes attach a typed payload:
if (e.code == AhpErrorCodes.unsupportedProtocolVersion) { final data = e.data; if (data is Map<String, Object?>) { print('host speaks: ${data['supportedVersions']}'); print('we offered: $supportedProtocolVersions'); }}unsupportedProtocolVersion is terminal, and it is the clearest example of why
the retry column above matters. The client already offered every version it can
speak — there is nothing left to degrade to, and a retry loop will fail
identically forever. The fix is a newer client.
The payload has a generated type, so it is worth decoding rather than reaching into the map:
on AhpRpcException catch (e) { if (e.code == AhpErrorCodes.unsupportedProtocolVersion) { final data = UnsupportedProtocolVersionErrorData.fromJson( e.data! as Map<String, Object?>, ); print('host speaks ${data.supportedVersions}'); }}Note those may be SemVer ranges rather than exact versions — a real host
answers ^0.7.0, so comparing them for equality against
supportedProtocolVersions will not do what you want.
authRequired carries AuthRequiredErrorData, and permissionDenied carries
PermissionDeniedErrorData.
Decode failures
Section titled “Decode failures”AhpDecodeException names the type and the field:
AhpDecodeException: ChatState.activeTurn: required field missingThat specificity is deliberate. Without it, a missing required field surfaces
as type 'Null' is not a subtype of type 'String' from somewhere inside a
generated constructor, which tells you nothing about which payload was wrong.
Seeing one means the host sent something the schema does not describe. Either the vendored schema is behind the host, or the host has a bug. It is not a condition to handle at runtime — it is one to report.
Unknown variants are not errors
Section titled “Unknown variants are not errors”A type this client does not recognize is not a decode failure. It decodes to
the union’s Unknown variant, keeps the raw JSON, and re-encodes unchanged.
The specification requires clients to ignore what they do not understand, and
reducers treat those as no-ops. See Actions.