Skip to content
Portal Control Protocol

Error Codes

PCP errors exist at three layers. The outermost layer is the wire protocol, which uses HTTP-style numeric codes in ErrorResponsePayload { code, message } on the client socket. The middle layer is the core PcpError enum, which the daemon uses internally for structured error handling. The innermost layer covers transport and framing errors that arise before any protocol logic runs.

Capability-level failures do not arrive as error frames. They return success: false results with an error description in the response payload. This distinction matters because it separates “the protocol broke” from “the capability failed.”

These codes travel over the socket in ErrorResponsePayload. They indicate problems at the protocol or daemon level, not at the capability level.

Code Meaning
400 Unsupported message type, malformed payload, or decode failure
404 Capability or app not found
429 Rate limit exceeded (100 requests/second/connection)
500 Adapter or execution failure
503 Daemon unhealthy or adapter unavailable
504 Execution timeout (30 seconds)

A 400 means the client sent something the daemon cannot parse. This is a client bug, not a transient failure. A 404 means the target capability or application does not exist in the registry. A 429 is the rate limiter rejecting a request before it reaches the dispatcher. A 500 is a catch-all for adapter-level failures. A 503 means the daemon itself is in a bad state (for example, an adapter crashed and has not been replaced). A 504 means the capability took too long to execute.

The 429 response fires immediately, before the request reaches the dispatcher. This is intentional: rate-limited requests should not consume any resources beyond the rate check itself.

The core PcpError enum covers every failure mode the daemon can encounter. These are structured errors that carry context about what went wrong, making them useful for logging, debugging, and client-side error handling.

Variant Meaning
CapabilityNotFound The requested capability does not exist in the registry
AdapterUnavailable The adapter for the target capability is not running or has crashed
RegistryError A registry operation (register, unregister, query) failed
Variant Meaning
PermissionDenied The requester lacks the auth level for this capability
ConfirmationError The confirmation gate rejected the request (expired, denied, or malformed token)
Variant Meaning
ExecutionFailed The capability invocation returned an error from the adapter or target app
DetectionFailed The adapter could not detect capabilities for the target application
Timeout The operation exceeded its configured timeout
Variant Meaning
AuditError Writing to or reading from the audit log failed
SupervisionError The supervision or health monitoring system reported an error
RateLimitExceeded The per-connection rate limit was exceeded
Variant Meaning
InvalidParameters One or more parameters failed validation (reason field explains what)
TransactionAborted A multi-step transaction was aborted (rollback attempted or skipped)
SerializationError Structured data could not be serialized or deserialized
Variant Meaning
ConnectionError The underlying IPC connection dropped or failed to establish
AuthenticationFailed Auth handshake failed (reason field explains what)
ManifestValidationError A capability manifest failed structural or schema validation
Variant Meaning
EventError Publishing or delivering an event failed (subscription issues, channel overflow)

IpcError covers failures on the Tier 1 IPC path. These occur when the daemon talks to Tier 1 applications over Unix domain sockets.

Variant Meaning
ConnectionFailed Could not establish a connection to the target app’s socket
Protocol The app sent a message that violates the PCP framing protocol
Serialization Postcard or JSON encode/decode failed on the IPC path
AppNotReachable { app_id } The app’s socket exists but the app is not responding
UnexpectedMessageType Received a message type that does not belong in the current exchange
ConnectionClosed The app closed the connection mid-exchange

ProtocolError covers low-level framing failures. These occur during deserialization of raw bytes into protocol messages, before any semantic processing happens.

Variant Meaning
BadMagic The frame header magic bytes do not match the expected value
BadVersion The protocol version in the header is not supported
Truncated The frame is shorter than the header indicates
ChecksumMismatch The frame checksum does not match the payload
UnknownMessageType The message type code is not recognized
Postcard Postcard deserialization failed on the frame payload
Io An underlying I/O error occurred while reading or writing the frame

Wire errors follow the ErrorResponsePayload structure:

{
"code": 404,
"message": "capability not found: mail.send for app com.example.mailclient"
}

Capability-level failures arrive differently, as success: false results:

{
"id": 1,
"result": {
"success": false,
"error": "ExecutionFailed",
"reason": "target element no longer exists"
}
}

The distinction matters for clients. A wire error (code in the 400-504 range) means the request itself was rejected. A success: false result means the request was valid but the capability could not execute it.

Not all errors should be retried automatically.

Never retry parse errors (400), malformed payloads, or manifest validation failures. The payload or configuration itself is broken.

Respect rate limits (429). Back off with exponential delay. Start at 1 second, double on each failure, cap at 30 seconds. The rate limit is 100 requests per second per connection.

Retry transient failures once. Connection errors (503), timeouts (504), and adapter unavailability may resolve on the next attempt. If the same request fails twice in a row, stop and report.

Re-query state before retrying 404 errors. If a capability or app was not found, something may have changed. Fetch a fresh registry state before retrying.

Stop after three consecutive failures with an execution error. Looping indefinitely wastes resources and may amplify an already-degraded situation.

Last updated: