neondatabase/neon · error
could not parse config file: {}
Error message
could not parse config file: {} What it means
On the test-only configuration path, compute_ctl tried to serde-parse the file at params.config_path_test_only as a ComputeConfig JSON document and serde failed. The error chain includes the serde message with line/column. Production always takes the control-plane path instead; this fires only when config_path_test_only is explicitly set.
Source
Thrown at compute_tools/src/configurator.rs:81
// Drop the lock guard here to avoid holding the lock while downloading config from the control plane / HCC.
// This is the only thread that can move compute_ctl out of the `RefreshConfiguration` state, so it
// is safe to drop the lock like this.
drop(state);
let get_config_result: anyhow::Result<ComputeConfig> =
if let Some(config_path) = &compute.params.config_path_test_only {
// This path is only to make testing easier. In production we always get the config from the HCC.
info!(
"reloading config.json from path: {}",
config_path.to_string_lossy()
);
let path = Path::new(config_path);
if let Ok(file) = File::open(path) {
match serde_json::from_reader::<File, ComputeConfig>(file) {
Ok(config) => Ok(config),
Err(e) => {
error!("could not parse config file: {}", e);
Err(anyhow::anyhow!("could not parse config file: {}", e))
}
}
} else {
error!(
"could not open config file at path: {:?}",
config_path.to_string_lossy()
);
Err(anyhow::anyhow!(
"could not open config file at path: {}",
config_path.to_string_lossy()
))
}
} else if let Some(control_plane_uri) = &compute.params.control_plane_uri {
get_config_from_control_plane(control_plane_uri, &compute.params.compute_id)
} else {
Err(anyhow::anyhow!("config_path_test_only is not set"))
};
View on GitHub (pinned to 8f60b04da4)
Solutions
- Validate the file is well-formed JSON first (jq . config.json)
- Diff the document against the ComputeConfig serde schema of the compute_ctl build you run (fields, nesting, types)
- Regenerate the config file from a known-good source or copy an example from the repo's test fixtures
- Keep humans out of the loop: write the file atomically from tooling to avoid truncation
Example fix
// before
let path = Path::new(config_path);
if let Ok(file) = File::open(path) { serde_json::from_reader::<File, ComputeConfig>(file) ... }
// after: surface serde position instead of a generic re-wrap
match serde_json::from_reader::<File, ComputeConfig>(file) {
Ok(config) => Ok(config),
Err(e) => Err(anyhow!("could not parse config file at {}: {e}", config_path.display())),
} Defensive patterns
Strategy: validation
Validate before calling
// Validate before compute_ctl reads it
let raw = std::fs::read_to_string(path)?;
serde_json::from_str::<ComputeConfig>(&raw)
.map_err(|e| anyhow!("config at {path} is not a valid ComputeConfig: {e}"))?; Type guard
fn is_parseable_compute_config(path: &Path) -> bool {
std::fs::File::open(path).ok()
.and_then(|f| serde_json::from_reader::<_, ComputeConfig>(f).ok())
.is_some()
} Prevention
- Lint config files with a JSON schema/serde check in CI before deployment
- Generate configs programmatically and write atomically (tmp + rename) to avoid truncated files
- On compute_ctl upgrades, re-validate existing config fixtures against the new schema
When it happens
Trigger: configurator runs with --config-path-test-only (or equivalent param) pointing at a file that is valid enough to open but is not parseable as ComputeConfig: malformed JSON, wrong field types, unknown/renamed required fields.
Common situations: Hand-edited config.json with trailing commas or comments (not valid JSON); schema drift after upgrading compute_ctl (fields renamed/typed differently); pointing the flag at a ComputeSpec file instead of a ComputeConfig wrapper; file truncated mid-write.
Related errors
- could not open config file at path: {}
- connection to postgres closed
- pageserver connection information should be provided
- safekeeper connstrings should be provided
- tenant id should be provided
AI-assisted analysis of neondatabase/neon@8f60b04da4 (2026-08-16).
Data as JSON: /api/errors/99c6c482b5d4add9.
Report an issue: GitHub.