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
- Validate the file at the printed path with a JSON parser (jq . apps.json) and fix the reported syntax error.
- Diff the document's shape against a known-good plugin's apps config.
- Update the plugin to a version matching the host's codex-connectors schema, or update the host.
- 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
- Add a serde round-trip of the apps config to the plugin's CI.
- Pin plugin and host versions so declaration schemas stay aligned.
- Reject JSONC-style edits (comments, trailing commas) via a pre-commit JSON check.
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
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- failed to parse MCP config for selected plugin `{plugin_id}`
- queued submission payload is invalid: {0}
- failed to read app config for selected plugin `{plugin_id}`
- failed to read MCP config for selected plugin `{plugin_id}`
- failed to resolve MCP config path `{relative_path}` below se
AI-assisted analysis of openai/codex@339751715c (2026-08-25).
Data as JSON: /api/errors/124c2f4ba78877bf.
Report an issue: GitHub.