How to Handle Errors in an OpenAI Plugin: Complete Implementation Guide

OpenAI plugins handle errors by wrapping skill logic in try-except blocks and returning a standardized JSON payload with "ok": false, a numeric error code, and a safe user-facing message, as implemented in the openai/plugins repository.

OpenAI plugins are structured as collections of independent skills that require consistent error handling to communicate failures to the ChatGPT model. The openai/plugins repository establishes a strict error-handling contract that every skill must follow to ensure predictable, secure error responses. This guide explains the implementation pattern using actual source files from the repository.

The OpenAI Plugin Error-Handling Contract

Every skill in the repository follows a consistent contract to ensure the runtime can reliably parse success and failure states.

Standardized JSON Response Structure

On failure, skills must return a JSON object with an "ok": false field and an "error" object containing a numeric code and human-readable message. According to the UKB-TOPMed PheWAS skill documentation in plugins/life-science-research/skills/ukb-topmed-phewas-skill/SKILL.md, the contract requires:

{
  "ok": false,
  "error": {
    "code": 400,
    "message": "Human-readable description",
    "details": {}
  }
}

The "details" field is optional and should be omitted for privacy-critical errors.

Error Code Mapping and Security

Plugins map exceptions to stable HTTP-style error codes: 400 for bad input, 404 for not found, 500 for internal failures, and 502 for upstream service errors. The error message must never include stack traces, API keys, or internal tokens. As implemented in plugins/zotero/skills/zotero/scripts/zotero.py, sensitive information is filtered out to comply with OpenAI security policies while exceptions are logged internally for operator observability.

The _error.py Utility Implementation

The repository provides a shared utility to standardize error construction across all skills.

Centralized Error Builder

The build_error_response helper function is located at plugins/<plugin-name>/skills/<skill-name>/scripts/_error.py. This utility is explicitly defined in plugins/zotero/skills/zotero/scripts/_error.py and plugins/nvidia/skills/omniverse-cad-to-simready/shared/_error.py:

def build_error_response(exc: Exception, code: int = 500) -> dict:
    """Return a JSON-serialisable error payload."""
    # Never expose internal traceback – only the message.

    return {
        "ok": False,
        "error": {
            "code": code,
            "message": str(exc),
        },
    }

Integration in Skill Scripts

Each skill imports this helper and wraps its main logic in a try-except block. The Zotero skill in plugins/zotero/skills/zotero/scripts/zotero.py demonstrates this pattern:

from _error import build_error_response
import logging

def fetch_item(item_id: str):
    try:
        # ... network call to Zotero ...

        return {"ok": True, "item": data}
    except requests.HTTPError as exc:
        logging.exception("Zotero API failure")
        return build_error_response(exc, code=502)
    except Exception as exc:
        logging.exception("Unexpected Zotero error")
        return build_error_response(exc)

Real-World Error Handling Examples

The repository contains multiple implementations demonstrating how to handle different failure modes.

Life Science Research Skills

The UKB-TOPMed PheWAS skill in plugins/life-science-research/skills/ukb-topmed-phewas-skill/scripts/ukb_topmed_phewas.py maps specific exceptions to appropriate status codes:

import json
from _error import build_error_response

def main():
    try:
        # Parse input, call remote API, gather results ...

        result = {"association": [...]}
        return {"ok": True, "data": result}
    except ValueError as exc:               # e.g. malformed request

        return build_error_response(exc, code=400)
    except ConnectionError as exc:          # e.g. external service down

        return build_error_response(exc, code=502)
    except Exception as exc:                # unexpected bug

        return build_error_response(exc)    # defaults to 500

NVIDIA Omniverse Skills

The NVIDIA "Omniverse CAD → SimReady" skill uses the shared utility at plugins/nvidia/skills/omniverse-cad-to-simready/shared/_error.py. The file plugins/nvidia/skills/omniverse-cad-to-simready/shared/simready_package_check_dependencies.py demonstrates converting raised exceptions into structured error responses while maintaining debuggability through internal logging.

Summary

  • Return consistent shapes: Always return {"ok": false, "error": {...}} for failures and {"ok": true, ...} for successes.
  • Use the helper: Import build_error_response from _error.py to ensure consistent payload structure.
  • Map codes appropriately: Use 400 for client errors, 404 for missing resources, 502 for upstream failures, and 500 for internal errors.
  • Secure by default: Never expose stack traces, API keys, or tokens in error messages; log these internally using logging.exception().
  • Document in SKILL.md: Each skill defines its error contract in its SKILL.md file, such as plugins/zotero/skills/zotero/SKILL.md.

Frequently Asked Questions

What JSON structure should error responses follow in OpenAI plugins?

Error responses must return a JSON object with "ok": false and an "error" object containing "code" (integer), "message" (string), and optionally "details" (dictionary). This contract is documented in skill definition files like plugins/life-science-research/skills/ukb-topmed-phewas-skill/SKILL.md and enforced by the build_error_response utility.

Where is the error handling utility located in the openai/plugins repository?

The shared helper is typically located at plugins/<plugin-name>/skills/<skill-name>/scripts/_error.py. Specific implementations exist in plugins/zotero/skills/zotero/scripts/_error.py and plugins/nvidia/skills/omniverse-cad-to-simready/shared/_error.py, which are imported by individual skill scripts to standardize error formatting.

How do OpenAI plugins prevent sensitive data leaks in error messages?

Plugins use the build_error_response function to ensure only the exception message is returned, omitting stack traces and secret values. Internal details are logged using logging.exception() for operator visibility, while the JSON response contains only user-safe text, as required by the OpenAI security policies implemented in the plugin runtime.

What error codes should OpenAI plugin skills return?

Use standard HTTP-style codes: 400 for client input errors, 404 for missing resources, 502 for upstream service failures (like external API outages), and 500 for unexpected internal errors. The Zotero skill in plugins/zotero/skills/zotero/scripts/zotero.py demonstrates mapping specific exceptions like requests.HTTPError to code 502.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →