Errors
The ErrorInfo type that every AI Transport failure path surfaces, the numeric codes you match against, and the patterns for handling errors on the client and the agent.
Every rejected promise and every error event carries an ErrorInfo object. The same type covers AI Transport-specific failures, Ably platform errors (auth, channel attach, rate limits), and underlying network errors. Match against a specific code with the errorInfoIs utility.
ErrorInfo
The ErrorInfo type is exported from ably. AI Transport surfaces it as the rejection reason on every promise that can fail, and as the argument to every on('error') listener on a transport.
Properties
codeNumbererrorInfoIs to identify a specific failure.messageStringstatusCodeNumbercauseErrorInfo or UndefineddetailRecord<string, string> or UndefinedAI Transport error codes
General errors
| Code | Name | HTTP status | Description | Recovery |
|---|---|---|---|---|
| 40003 | InvalidArgument | 400 | An argument was invalid. For example, a header value that is not a string, number, boolean or null, an event that send() cannot publish because the codec encodes it as an append, a pageSize or maxPages below one, or a hook used outside a TransportProvider. | Check the argument against the API reference for the method. |
| 40033 | OperationCancelled | 400 | The operation was cancelled. A pipe's abort signal fired, the transport closed during a pipe, or a subscription unsubscribed or the transport closed during a history replay. A cancelled pipe finishes the messages it has written before it rejects. | Expected after a deliberate cancel. Treat it as a normal outcome rather than a failure to retry. |
| 40160 | InsufficientCapability | 401 | The Ably channel rejected a publish because the token does not permit it. | Add the publish capability for the channel to the token. |
| 50000 | InternalError | 500 | The SDK or the Ably service behaved in a way the SDK cannot explain, for example a publish that succeeded but returned no serial. | Retry the operation. |
Transport errors
The names of these codes start with Session to match the Ably error registry. They are transport errors.
| Code | Name | HTTP status | Description | Recovery |
|---|---|---|---|---|
| 104000 | StreamedMessageFinalizeFailed | 500 | An append to a streamed message failed, and the update that would have repaired it with the full content failed too. The partial message stays on the channel. The first failure is the cause. | Check connectivity, and decide whether to publish the response again. |
| 104001 | SessionSubscriptionFailed | 500 | The transport could not subscribe to and attach its channel on the first subscribe(). Nothing is delivered until the attach succeeds. Reported on the transport's error event. | Inspect the cause. A transient disconnect clears when the next subscribe() tries again. A capability or auth rejection needs a token change. |
| 104004 | SessionClosed | 400 | A method was called on a transport that has already been closed. | Create a new transport. |
| 104005 | SessionSendFailed | 500 | A publish through send() failed for a reason other than capability. The Ably failure is the cause. | Inspect the cause, and check the connection state. |
| 104008 | PipeFailed | 500 | A pipe failed for one of these reasons: the source stream threw, such as on a provider rate limit or a model error; the codec could not encode an event; a publish or update failed; or the repair of a stream failed. The underlying failure is the cause. | Inspect the cause for the provider error. |
| 104009 | SessionMessageProcessingFailed | 500 | The codec threw while decoding an inbound message. The message is still delivered with no event, and the subscription carries on. Reported on the transport's error event. | Check the codec's decode for the message type. |
| 104011 | SessionHistoryFetchFailed | 500 | The transport could not read history as asked. A history page could not be fetched after retries, with the original failure as cause. A history replay also fails with this code when its replay function throws, or when fromSerial or untilEvent set to onExhausted: 'error' runs out of pages. Surfaced by history(), next(), a subscription's replayed, and useHistory's error. | Inspect the cause. Retry the read, and check the history capability on the token if it persists. |
Auth and channel errors
Auth and channel errors come from the Ably platform rather than AI Transport. The most common codes you encounter:
| Code | Description | Recovery |
|---|---|---|
| 40142 | Token expired. | Refresh the token (handled automatically with authUrl/authCallback). |
| 40300 | Forbidden. | The token is valid but not authorised for this resource. |
| 80000 | Channel attach failed. | Check the channel name and capability. |
| 90000 | Internal channel error. | Retry the operation. If the error persists, contact support. |
| 93002 | Can only update/delete/append messages on channels with mutableMessages enabled. No channel rule with mutableMessages matches the channel, so AI Transport cannot append stream tokens. This is the most common AI Transport setup failure. | Enable the Message annotations, updates, deletes, and appends rule on the channel. |
The Ably error codes page lists every code the platform returns.
Match an ErrorInfo against a code
errorInfoIs(errorInfo: Ably.ErrorInfo, error: ErrorCode): booleanerrorInfoIs returns true if the ErrorInfo's code matches the supplied ErrorCode. Use it in error handlers to branch on a specific failure by its numeric code.
1
2
3
4
5
6
7
8
import { errorInfoIs, ErrorCode } from '@ably/ai-transport';
try {
await transport.pipe(stream, { signal: req.signal });
} catch (error) {
if (errorInfoIs(error, ErrorCode.OperationCancelled)) return;
throw error;
}Example
The agent treats a cancelled pipe as a normal outcome and reports any other failure. The client logs the errors the transport reports with no caller to reject, and handles a history replay that failed.
1
2
3
4
5
6
7
8
9
10
11
12
13
// Agent code.
import * as Ably from 'ably';
import { ErrorCode, errorInfoIs } from '@ably/ai-transport';
try {
await transport.pipe(stream, { signal: req.signal });
return new Response(null, { status: 204 });
} catch (error) {
const cancelled = error instanceof Ably.ErrorInfo && errorInfoIs(error, ErrorCode.OperationCancelled);
return new Response(null, { status: cancelled ? 204 : 500 });
} finally {
await transport.close();
}1
2
3
4
5
6
7
8
9
10
11
12
13
// Client code.
import { fromSerial } from '@ably/ai-transport';
transport.on('error', (error) => {
console.error(`Error ${error.code}: ${error.message}`);
});
const subscription = transport.subscribe(apply, { history: { replay: fromSerial(storedSerial) } });
subscription.replayed.catch((error) => {
// The handler is live, with a gap where the replay would have been.
showWarning(`Could not load earlier messages: ${error.message}`);
});