warpdotdev/warp · error · anyhow::Error
Failed to parse Codex TOML: {e}
Error message
Failed to parse Codex TOML: {e} What it means
`normalize_codex_toml_to_json` (feature `local_fs`) parses a Codex `config.toml` with `toml::from_str::<toml::Value>` before normalizing `mcp_servers` entries into JSON. This error means the file is not valid TOML syntax at all — it fires at the whole-file parse. Per-entry type mismatches (an entry matching neither Stdio nor Http) are intentionally tolerated later via `filter_map(... .ok())` and do NOT produce this error.
Source
Thrown at app/src/ai/mcp/parsing.rs:159
JSONTransportType::SSEServer {
url,
headers: merged_headers,
}
}
}
}
}
/// Normalizes the contents of a Codex `config.toml` into a JSON string
/// compatible with `ParsedTemplatableMCPServerResult::from_user_json`.
#[cfg(feature = "local_fs")]
pub(crate) fn normalize_codex_toml_to_json(file_contents: &str) -> Result<String, anyhow::Error> {
// Parse into a raw Value first so we can handle per-entry deserialization failures
// gracefully. Using HashMap<String, CodexServerEntry> directly would cause the entire
// parse to fail if any single entry matches neither Stdio nor Http.
let raw: toml::Value = toml::from_str(file_contents)
.map_err(|e| anyhow::anyhow!("Failed to parse Codex TOML: {e}"))?;
let out_servers: HashMap<String, JSONMCPServer> = raw
.get("mcp_servers")
.and_then(|v| v.as_table())
.map(|table| {
table
.iter()
.filter_map(|(name, val)| {
val.clone()
.try_into::<CodexServerEntry>()
.ok()
.map(|entry| {
(
name.clone(),
JSONMCPServer {
transport_type: JSONTransportType::from(entry),
},
)View on GitHub (pinned to e72fd7aacb)
Solutions
- Validate the file with a TOML linter/editor with TOML LSP — the wrapped {e} includes the line/column of the syntax error
- Fix common TOML mistakes: quote string values, use [mcp_servers.name] tables, close all brackets and strings
- Restore from backup or re-create the file if it was truncated by a concurrent write
- Write config files atomically (temp file + rename) so watchers never observe partial content
Example fix
# before (invalid TOML: unquoted command, stray trailing token) [mcp_servers.fetch] command = npx args = [-y, fetch-mcp] extra # after [mcp_servers.fetch] command = "npx" args = ["-y", "fetch-mcp"]
Defensive patterns
Strategy: validation
Validate before calling
// Validate TOML before normalizing; surface the span to the user instead of failing late.
if let Err(e) = toml::from_str::<toml::Value>(&file_contents) {
let offset = e.span().map(|s| s.start).unwrap_or(0);
return Err(anyhow!("config.toml is invalid TOML near offset {offset}: {e}"));
} Type guard
fn is_valid_toml(contents: &str) -> bool {
toml::from_str::<toml::Value>(contents).is_ok()
} Try / catch
match normalize_codex_toml_to_json(&file_contents) {
Ok(json) => json,
Err(e) if e.to_string().contains("Failed to parse Codex TOML") => {
// surface as a per-file config diagnostic and skip this provider
diagnostics.push(FileMCPConfigDiagnostic { kind: Parse, message: e.to_string(), .. });
continue;
}
Err(e) => return Err(e),
} Prevention
- Edit TOML with an editor that has TOML language support / LSP
- Write config files atomically (temp file + rename) so watchers never read partial files
- Keep a known-good backup of config.toml before hand-editing
When it happens
Trigger: The Codex config file has a TOML syntax error: unclosed table or string, duplicate keys, missing `=` or quotes, malformed arrays/indentation, a BOM, or a truncated file read mid-write by the file watcher.
Common situations: Hand-editing config.toml and leaving a syntax mistake; pasting JSON (not TOML) into config.toml; two tools writing the file concurrently so the watcher reads a half-written file; tabs breaking multiline arrays.
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
- Missing or empty environment variable: {var_name}
- SKILL.md missing frontmatter (no opening ---)
- SKILL.md missing frontmatter (no closing ---)
- {role}_settings_unavailable_or_invalid
- source_config_unavailable
AI-assisted analysis of warpdotdev/warp@e72fd7aacb (2026-08-16).
Data as JSON: /api/errors/0915de69a6a60195.
Report an issue: GitHub.