How to Describe Error Handling in an OpenAI Plugin's API: A Complete Technical Guide
OpenAI plugins communicate failures through structured JSON error objects containing error, code, and status fields, using standard HTTP status codes defined in the OpenAPI specification to ensure the ChatGPT runtime can surface safe, actionable messages without exposing internal implementation details.
The openai/plugins repository demonstrates that robust error handling is contractual rather than optional. Each plugin describes its failure modes through an OpenAPI specification, while skill implementations wrap external API calls in defensive try/except blocks to translate exceptions into machine-readable payloads. This approach prevents raw stack traces from reaching the LLM while preserving diagnostic information for developers.
The OpenAPI Error Contract
Defining HTTP Status Codes and Response Schemas
Every plugin declares its API surface via a plugin.json manifest that points to an external OpenAPI specification. According to the Sentry plugin configuration in plugins/sentry/.codex-plugin/plugin.json, the api.url field references a schema that must define standard HTTP status codes: 4xx for client errors such as invalid parameters or authentication failures, and 5xx for server-side failures. The OpenAPI schema must declare a consistent error response object structure that the ChatGPT runtime can reliably parse.
Standard Error Payload Structure
The runtime expects a uniform JSON shape when operations fail. The payload must include:
error: A human-readable string describing the failurecode: A machine-parseable error identifier (e.g.,TIMEOUT,HTTP_ERROR)status: The HTTP status code integerdetails: Optional additional context for complex failure scenarios
This structure ensures the ChatGPT client can display helpful messages without executing or exposing arbitrary error content to the conversation context.
Implementing Error Handlers in Plugin Skills
Wrapping External API Calls
Skill scripts must isolate third-party API failures to prevent cascading errors. In plugins/nvidia/skills/omniverse-cad-to-simready/references/preflight/scripts/preflight.py, the implementation wraps external operations in try/except blocks to catch network timeouts and validation errors before they propagate. When an external service returns a non-2xx response or raises a connection error, the script constructs a JSON payload with the standardized fields rather than allowing the raw exception to surface to the LLM.
Exception Logging and Safe Failures
The plugins/ngs-analysis/scripts/run_scrnaseq_fastq_to_count.py file demonstrates the critical pattern of logging detailed tracebacks to persistent storage while returning generic error messages to the runtime. When an unexpected exception occurs, the script writes the full traceback to runner_exception.txt on disk, then returns a sanitized payload to the user. This prevents internal implementation details from leaking into the LLM context while maintaining debuggability for plugin developers.
Explicit Exception Status Flags
Some plugins use an explicit status: "exception" field in their response payloads to signal the runtime that the operation encountered a fatal error rather than returning partial data. This pattern appears in NVIDIA's pre-flight checks within preflight.py, where the script must distinguish between successful data retrieval and workflow-blocking errors that require immediate user intervention.
Practical Error Handling Examples
Python: Defensive Wrapper with Logging
Based on patterns from preflight.py and the NGS analysis scripts:
import json
import requests
from typing import Dict, Any
def call_external_api(endpoint: str, params: Dict[str, Any]) -> Dict[str, Any]:
"""
Execute an external API call with standardized error translation.
"""
try:
response = requests.post(endpoint, json=params, timeout=30)
response.raise_for_status()
return response.json()
except requests.HTTPError as http_err:
# Translate HTTP errors into plugin-compatible format
return {
"error": f"External service error: {response.status_code}",
"code": "EXTERNAL_API_ERROR",
"status": response.status_code
}
except Exception as exc:
# Log full traceback for debugging, return safe message
with open("logs/runner_exception.txt", "a") as log_file:
log_file.write(f"{type(exc).__name__}: {exc}\n")
return {
"error": "Internal plugin error occurred. Check logs for details.",
"code": "INTERNAL_ERROR",
"status": 500,
"status_flag": "exception" # Explicit error signal
}
JavaScript: Node.js Fetch Implementation
For Node.js-based plugins, implement similar defensive patterns:
import fetch from 'node-fetch';
/**
* Execute plugin endpoint with uniform error handling.
*/
export async function executeSkill(url, payload) {
try {
const response = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
if (!response.ok) {
const errorText = await response.text();
return {
error: `Plugin request failed: ${errorText}`,
code: 'HTTP_ERROR',
status: response.status
};
}
return await response.json();
} catch (networkError) {
return {
error: `Network failure: ${networkError.message}`,
code: 'NETWORK_ERROR',
status: 502
};
}
}
OpenAPI Specification Snippet
Define error responses in your OpenAPI document to satisfy the contract:
paths:
/analyzeData:
post:
summary: Analyze external data source
responses:
'200':
description: Successful analysis
content:
application/json:
schema:
type: object
properties:
result:
type: string
'4XX':
description: Client error
content:
application/json:
schema:
type: object
required: [error, code, status]
properties:
error:
type: string
description: Human-readable error message
code:
type: string
description: Machine-readable error code
status:
type: integer
description: HTTP status code
'5XX':
description: Server error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
Summary
- Standardize on JSON: Always return error objects containing
error,code, andstatusfields to maintain compatibility with the ChatGPT runtime. - Use OpenAPI contracts: Define all 4xx and 5xx responses in the OpenAPI specification referenced by your
plugin.jsonmanifest. - Log internally, sanitize externally: Write full tracebacks to files like
runner_exception.txtas shown inplugins/ngs-analysis/scripts/run_scrnaseq_fastq_to_count.py, but return generic messages to the API consumer. - Wrap external calls: Isolate third-party failures using
try/exceptblocks that translate exceptions into the standardized payload format. - Signal explicitly: Use
status: "exception"flags where appropriate to distinguish between partial data and fatal errors.
Frequently Asked Questions
What HTTP status codes should an OpenAI plugin return for errors?
Return 4xx status codes for client-side issues such as invalid parameters or missing authentication, and 5xx codes for server-side failures or upstream service outages. The OpenAPI specification referenced in your plugin.json must document these response codes and their corresponding JSON schemas to ensure the runtime can parse them correctly.
How do I prevent sensitive error details from leaking to the ChatGPT user?
Wrap all operations in try/except blocks and write full exception tracebacks to internal log files (e.g., runner_exception.txt) rather than returning them in the API response. Return only sanitized JSON payloads containing a generic error message, a machine-readable code, and the HTTP status. This pattern appears in plugins/ngs-analysis/scripts/run_scrnaseq_fastq_to_count.py within the repository.
Should I use custom exception classes in my plugin code?
Yes, defining custom exception classes improves code organization and enables precise error translation. The plugins/mixpanel-headless/skills/mixpanelyst/scripts/help.py file demonstrates enumerating custom exception types to document expected failure modes. However, these should be caught and converted to the standard JSON error format before being returned through the API.
How does the ChatGPT runtime know when a plugin function failed?
The runtime inspects the HTTP status code and the response body structure. If the response contains an error field or a status: "exception" flag (as implemented in plugins/nvidia/skills/omniverse-cad-to-simready/references/preflight/scripts/preflight.py), the runtime interprets this as a failure and surfaces the contained message to the user rather than attempting to process the payload as successful data.
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 →