{"record":{"id":"b52d8c650b5a59c3","repo":"astrid-runtime/astrid","slug":"existing-security-capsule-local-egress-capsule","errorCode":null,"errorMessage":"existing [security.capsule_local_egress].{capsule_id} is not an array","messagePattern":"existing \\[security\\.capsule_local_egress\\]\\.(.+?) is not an array","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/capsule/local_egress.rs","lineNumber":155,"sourceCode":"        toml_edit::DocumentMut::new()\n    };\n\n    // Navigate / create `[security.capsule_local_egress]`.\n    let security = doc[\"security\"].or_insert(toml_edit::table());\n    if let Some(t) = security.as_table_mut() {\n        // Keep the nested table from being rendered inline.\n        t.set_implicit(true);\n    }\n    let egress = doc[\"security\"][\"capsule_local_egress\"].or_insert(toml_edit::table());\n    if let Some(t) = egress.as_table_mut() {\n        t.set_implicit(true);\n    }\n\n    let list = doc[\"security\"][\"capsule_local_egress\"][capsule_id].or_insert(\n        toml_edit::Item::Value(toml_edit::Value::Array(toml_edit::Array::new())),\n    );\n    let Some(arr) = list.as_array_mut() else {\n        anyhow::bail!(\"existing [security.capsule_local_egress].{capsule_id} is not an array\");\n    };\n\n    // Idempotent: skip if already present (case-insensitive host match handled\n    // by the host enforcement; here exact-string is enough for the operator\n    // file's own dedup).\n    let already = arr\n        .iter()\n        .any(|v| v.as_str().is_some_and(|s| s.eq_ignore_ascii_case(entry)));\n    if !already {\n        arr.push(entry);\n    }\n\n    if let Some(parent) = config_path.parent() {\n        std::fs::create_dir_all(parent).with_context(|| format!(\"create {}\", parent.display()))?;\n    }\n    write_atomic(config_path, doc.to_string().as_bytes())\n        .with_context(|| format!(\"write {}\", config_path.display()))\n}","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/capsule/local_egress.rs#L137-L173","documentation":"record_local_egress parses the operator's config file with toml_edit and inserts host arrays under [security.capsule_local_egress].<capsule_id>. If the key already exists but its value is not a TOML array (e.g. a string or inline table), the code cannot append ports and bails with this message. It protects the config from being silently overwritten with a wrong type.","triggerScenarios":"Running a capsule command that records local egress hosts when the config already defines security.capsule_local_egress.<capsule_id> as a non-array TOML value (string, integer, table).","commonSituations":"Hand-edited config where a list was written as a quoted string ('host1, host2') or as an inline table; an older tool version wrote a different shape; copy-pasting config snippets with mismatched types.","solutions":["Open the config file and change the security.capsule_local_egress.<capsule_id> entry to a TOML array of strings, e.g. hosts = [\"example.local\"].","Remove the malformed key and re-run the command so it recreates the array correctly.","Validate the TOML file (e.g. with a TOML linter) after manual edits before running capsule commands."],"exampleFix":"// before (config.toml)\n[security.capsule_local_egress]\nmy-capsule = \"api.local, db.local\"\n// after\n[security.capsule_local_egress]\nmy-capsule = [\"api.local\", \"db.local\"]","handlingStrategy":"validation","validationCode":"let cfg: toml::Value = toml::from_str(&std::fs::read_to_string(path)?)?;\nlet bad = cfg.get(\"security\")\n    .and_then(|s| s.get(\"capsule_local_egress\"))\n    .and_then(|e| e.get(capsule_id))\n    .map(|v| !v.is_array())\n    .unwrap_or(false);\nif bad { eprintln!(\"fix [security.capsule_local_egress].{capsule_id}: must be an array\"); }","typeGuard":"fn is_host_array(v: &toml::Value) -> bool {\n    v.as_array().map_or(false, |a| a.iter().all(|x| x.is_str()))\n}","tryCatchPattern":"match record_local_egress(...).await {\n    Err(e) if e.to_string().contains(\"is not an array\") => {\n        // back up config, rewrite the key as an array, retry\n    }\n    r => r?,\n}","preventionTips":["Hand-edit egress lists only as TOML arrays of strings.","Run a TOML validator after manual config edits.","Keep one writer (the CLI) for this config section to avoid shape drift."],"tags":["toml","config","type-mismatch"],"backgroundTag":"config-type-mismatch","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}