Troubleshooting Common PI Desktop Errors: A Complete Guide to Result Types and Error Codes
PI Desktop uses a unified Result<T> discriminated union and AppError type to standardize error handling across network, tool, permission, and plugin failures, enabling consistent retry logic and user messaging.
PI Desktop (vastsa/PI-Desktop) implements a robust error-handling architecture that replaces thrown exceptions with structured result types. Instead of crashing or returning ambiguous null values, every public API returns a Result object containing either success data or detailed error metadata. This pattern ensures that UI layers, extension developers, and internal agents handle failures in a predictable, type-safe manner.
Core Error Architecture in PI Desktop
The AppError Type and Result Pattern
At the heart of PI Desktop’s error system lies the AppError type defined in packages/shared/src/errors.ts. This interface encapsulates everything needed to diagnose and recover from failures:
code: A string identifier from the centralErrorCodesenum (e.g.,NETWORK_ERROR,TOOL_DENIED)message: A human-readable description suitable for UI displaydetails: Optional structured data containing HTTP status codes, stack traces, or underlying exception informationretriable: A boolean flag indicating whether the operation can safely be retriedtraceId: A unique identifier for correlating errors across distributed logs
The Result<T> type is a discriminated union representing either success or failure:
type Result<T> =
| { ok: true; data: T }
| { ok: false; error: AppError };
According to the vastsa/PI-Desktop source code, this pattern forces consumers to explicitly handle both branches, eliminating undefined behavior from unhandled exceptions.
The ErrorCodes Enum
All error identifiers are centralized in the ErrorCodes enum within packages/shared/src/errors.ts. This registry includes exhaustive codes covering network providers, tool execution, permissions, plans, plugins, and host-core failures. By standardizing codes, the codebase ensures that a NETWORK_ERROR returned from agent-sidecar.ts triggers the same UI behavior as one returned from a plugin.
Common PI Desktop Error Categories
Network and Provider Failures
Network errors occur when PI Desktop cannot reach external model providers such as OpenAI, Anthropic, or Ollama. Common codes include NETWORK_ERROR, PROVIDER_ERROR, PROVIDER_RATE_LIMITED, and PROVIDER_UNAUTHORIZED. These errors typically originate in apps/desktop/electron/main/agent-sidecar.ts when HTTP requests fail or return non-2xx status codes. When encountering these errors, check the details property for the specific HTTP status and URL.
Tool and Skill Execution Errors
Agent-side tools—such as filesystem operations or shell commands—emit errors like TOOL_NOT_FOUND, TOOL_DENIED, TOOL_TIMEOUT, TOOL_FAILED, and TOOL_ABORTED. These surface when a user blocks a privileged action or when a tool crashes during execution. The UI displays these as red badges in the tool panel, while logs contain the full AppError object with diagnostic context.
Permission and Access Control Errors
Permission errors prevent unauthorized actions through codes like PERMISSION_REQUIRED, PLUGIN_PERMISSION_DENIED, and WORKSPACE_PATH_DENIED. Unlike other error types, these often trigger interactive prompts asking the user to approve the action. If the user ignores or rejects the prompt, the system returns a PERMISSION_REQUIRED error with retriable set to true, allowing the UI to re-prompt later.
Plan and Goal Execution Errors
Plan-mode operations fail with codes such as PLAN_APPROVAL_TIMEOUT, PLAN_EXECUTION_FAILED, and PLAN_INVALID_ACTION. As implemented in apps/desktop/electron/main/plan-execution.ts, these errors occur when users do not approve a generated plan within the timeout window or when the execution engine cannot perform a planned action. The Plan UI panel displays yellow warning indicators containing the AppError message.
Plugin and MCP Integration Errors
Plugin lifecycle failures use codes including PLUGIN_INVALID, PLUGIN_LOAD_FAILED, and MCP_INVALID. Generated in apps/desktop/electron/main/plugin-runtime.ts, these errors indicate corrupted plugin manifests, missing dependencies, or Model-Context-Protocol (MCP) server communication failures. The Plugin Marketplace UI surfaces these failures while detailed logs are written to the main process output.
Host-Core and Internal Errors
Rust host process issues emit codes like HOST_UNAVAILABLE, HOST_OVERLOADED, HOST_SHUTTING_DOWN, SESSION_NOT_FOUND, INTERNAL, and APP_DEGRADED. These indicate SQLite corruption, missing sessions, or resource exhaustion in the Electron main process. When the host encounters these states, it writes to the application log and notifies the renderer process to display degradation warnings.
Handling PI Desktop Errors Programmatically
To work with PI Desktop’s error system, import the ok and err constructors from packages/shared/src/errors.ts:
import { err, ok, Result } from "./errors.js";
// Wrapping a model provider call
async function fetchCompletion(prompt: string): Promise<Result<string>> {
try {
const response = await fetch("https://api.provider.com/v1/chat", {
method: "POST",
body: JSON.stringify({ prompt })
});
if (!response.ok) {
// Return a structured error instead of throwing
return err(
"NETWORK_ERROR",
`Provider returned status ${response.status}`,
{ status: response.status, url: response.url },
true // retriable
);
}
const data = await response.json();
return ok(data.text);
} catch (e) {
return err(
"INTERNAL",
"Unexpected exception during fetch",
{ exception: e.message },
false
);
}
}
When consuming a Result, always check the ok flag before accessing data:
const result = await fetchCompletion("Explain monads");
if (!result.ok) {
console.error(`Error ${result.error.code}: ${result.error.message}`);
if (result.error.retriable) {
// Implement exponential backoff retry logic
setTimeout(() => fetchCompletion("Explain monads"), 1000);
}
} else {
console.log("Success:", result.data);
}
RACP Error Mapping for Remote Agents
PI Desktop includes the Remote Agent Control Protocol (RACP) for communicating with external agent processes. Located in packages/shared/src/racp.ts, this module ensures that errors crossing process boundaries remain interpretable.
The toRacpErrorCode function translates local error codes to remote protocol equivalents:
import { toRacpErrorCode } from "./racp.js";
const remoteCode = toRacpErrorCode("PERMISSION_TIMEOUT");
// Returns: "APPROVAL_EXPIRED"
The racpErrorIsRegistered helper verifies that a received remote code maps to a known ErrorCodes value, preventing unknown error propagation:
import { racpErrorIsRegistered, RACP_ERROR_CODES } from "./racp.js";
if (!racpErrorIsRegistered(remoteCode)) {
console.warn("Received unregistered remote error code");
}
This mapping layer ensures that a TOOL_DENIED error generated locally produces the same user-facing behavior as a remotely-generated equivalent received via RACP.
Summary
- PI Desktop returns
Result<T>objects instead of throwing exceptions, forcing explicit error handling through theokdiscriminant. - The
AppErrortype provides standardized fields:code,message,details,retriable, andtraceId. - All error codes are centralized in the
ErrorCodesenum withinpackages/shared/src/errors.ts. - Remote agent errors are normalized via the RACP protocol in
packages/shared/src/racp.tsusingtoRacpErrorCode()andracpErrorIsRegistered(). - Always check
result.okbefore accessingresult.data, and respect theerror.retriableflag when implementing recovery logic.
Frequently Asked Questions
What is the Result type in PI Desktop?
The Result<T> type is a discriminated union defined in packages/shared/src/errors.ts that represents either a successful value ({ ok: true, data: T }) or a failure ({ ok: false, error: AppError }). This pattern eliminates null pointer exceptions and forces developers to handle error cases explicitly at the type level.
How do I check if a PI Desktop error is retryable?
Inspect the retriable boolean property on the AppError object. If result.error.retriable is true, the operation can safely be retried after a delay or upon user request. Network timeouts and permission prompts typically set this flag to true, while validation errors and tool crashes set it to false.
Where are PI Desktop error codes defined?
All error codes are defined in the ErrorCodes enum located in packages/shared/src/errors.ts. This central registry includes codes for network failures (NETWORK_ERROR), tool denials (TOOL_DENIED), permission requirements (PERMISSION_REQUIRED), and host-core issues (HOST_UNAVAILABLE).
How does PI Desktop handle errors from remote agents?
PI Desktop uses the RACP (Remote Agent Control Protocol) mapping layer in packages/shared/src/racp.ts. The toRacpErrorCode() function translates local codes to remote equivalents (e.g., mapping PERMISSION_TIMEOUT to APPROVAL_EXPIRED), while racpErrorIsRegistered() ensures received codes map to known error types before being processed by the UI.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →