openai/codex · error · ExecutorPluginConnectorProviderError

failed to parse app config for selected plugin `{plugin_id}`

Error message

failed to parse app config for selected plugin `{plugin_id}` at `{path}`: {source}

What it means

The plugin's apps config file was read successfully but parse_plugin_app_config (serde_json) could not deserialize its contents into AppDeclaration values. The serde_json::Error source gives the exact line/column of the problem. This is a plugin packaging bug or a host/plugin schema version mismatch, not an environment issue.

Source

Thrown at codex-rs/ext/connectors/src/executor_plugin.rs:24

use codex_utils_path_uri::PathUri;
use std::io;
use thiserror::Error;

/// Loads connector declarations from a resolved plugin through its owning executor.
#[derive(Clone, Copy, Debug, Default)]
pub struct ExecutorPluginConnectorProvider;

/// Failure to load connector declarations from an executor plugin.
#[derive(Debug, Error)]
pub enum ExecutorPluginConnectorProviderError {
    #[error("failed to read app config for selected plugin `{plugin_id}` at `{path}`: {source}")]
    ReadConfig {
        plugin_id: String,
        path: PathUri,
        #[source]
        source: io::Error,
    },
    #[error("failed to parse app config for selected plugin `{plugin_id}` at `{path}`: {source}")]
    ParseConfig {
        plugin_id: String,
        path: PathUri,
        #[source]
        source: serde_json::Error,
    },
}

impl ExecutorPluginConnectorProvider {
    /// Returns the connector declarations contributed by `plugin`.
    #[tracing::instrument(name = "connectors.executor_plugin.declarations.load", skip_all)]
    pub async fn load(
        &self,
        plugin: &ResolvedExecutorPlugin,
    ) -> Result<Vec<AppDeclaration>, ExecutorPluginConnectorProviderError> {
        let resolved_plugin = plugin.plugin();
        let plugin_id = resolved_plugin.selected_root_id();
        let Some(PluginResourceLocator::Environment {

View on GitHub (pinned to 339751715c)

Solutions

  1. Validate the file at the printed path with a JSON parser (jq . apps.json) and fix the reported syntax error.
  2. Diff the document's shape against a known-good plugin's apps config.
  3. Update the plugin to a version matching the host's codex-connectors schema, or update the host.
  4. Add a CI step that serde-parses the config before packaging the plugin.

Example fix

// before (apps.json) — trailing comma
{ "apps": [ { "id": "db", "commands": "..." , ] }

// after
{ "apps": [ { "id": "db", "commands": "..." } ] }
Defensive patterns

Strategy: validation

Validate before calling

// Fail fast before host startup if the apps config is not even valid JSON
let raw = std::fs::read_to_string(&apps_config_path)?;
serde_json::from_str::<serde_json::Value>(&raw)
    .map_err(|e| anyhow::anyhow!("invalid apps config {apps_config_path}: {e}"))?;

Prevention

When it happens

Trigger: ExecutorPluginConnectorProvider::load on a plugin whose apps config is not valid JSON (trailing commas, comments, BOM) or whose structure does not match the expected app declaration schema (missing required fields, wrong types).

Common situations: Hand-edited apps config saved as JSONC/JSON5; plugin built against a newer or older declaration schema than the running host; empty file where an object was expected.

Understand the failure class

Related errors


AI-assisted analysis of openai/codex@339751715c (2026-08-25). Data as JSON: /api/errors/124c2f4ba78877bf. Report an issue: GitHub.