{"record":{"id":"c77a3596b6caa6fe","repo":"Hmbown/CodeWhale","slug":"source-is-not-valid-json-contents-omitted","errorCode":null,"errorMessage":"Source is not valid JSON; contents omitted","messagePattern":"Source is not valid JSON; contents omitted","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/mcp/external_import.rs","lineNumber":135,"sourceCode":"    }\n    out\n}\n\nfn discover_from_json_file(path: &Path, kind: ExternalMcpSourceKind) -> Vec<ImportCandidate> {\n    checked_source(path, kind).unwrap_or_default()\n}\n\nfn checked_source(\n    path: &Path,\n    kind: ExternalMcpSourceKind,\n) -> anyhow::Result<Vec<ImportCandidate>> {\n    super::validate_mcp_config_path(path)?;\n    let Some(raw) = super::read_mcp_config_file(path)? else {\n        return Ok(Vec::new());\n    };\n    let hash = hex_sha256(raw.as_bytes());\n    let value: Value = serde_json::from_str(&raw)\n        .map_err(|_| anyhow::anyhow!(\"Source is not valid JSON; contents omitted\"))?;\n    anyhow::ensure!(\n        value\n            .get(\"mcpServers\")\n            .or_else(|| value.get(\"servers\"))\n            .is_some_and(Value::is_object)\n            || value.is_array(),\n        \"Source has no supported MCP server map\"\n    );\n    let mut out = Vec::new();\n    for (name, mut config) in extract_servers_map(&value) {\n        anyhow::ensure!(\n            super::mcp_name_is_command_safe(&name) && name.len() <= 128,\n            \"Source contains an unsupported server name\"\n        );\n        if value.is_array()\n            && let Some(map) = config.as_object_mut()\n        {\n            map.remove(\"name\");","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/mcp/external_import.rs#L117-L153","documentation":"checked_source in crates/tui/src/mcp/external_import.rs reads a candidate external MCP source file and parses it as JSON before extracting servers. If serde_json::from_str fails, the file is not valid JSON and discovery aborts. The message omits contents on purpose — imported files may contain secrets.","triggerScenarios":"discover(path) or discover_from_json_file(path) pointing at a file that exists and is readable but whose text is not valid JSON (trailing commas, comments, JSONC, TOML, HTML error page).","commonSituations":"Importing another tool's JSONC-with-comments config; pointing at a config.json that is actually truncated; accidentally selecting a lockfile or an HTML download instead of the config.","solutions":["Validate the source file with jq . file or python -m json.tool, fix the syntax error, and retry discovery","Strip JSONC comments / trailing commas (convert to strict JSON) before importing","Point discovery at the correct file — verify the path is the actual config, not a log, lockfile, or downloaded page"],"exampleFix":"// before (source file: JSONC with comment — invalid JSON)\n{ // my servers\n  \"mcpServers\": { \"fs\": { \"command\": \"npx\" } } }\n// after\n{ \"mcpServers\": { \"fs\": { \"command\": \"npx\" } } }","handlingStrategy":"validation","validationCode":"fn source_is_valid_json(path: &std::path::Path) -> bool {\n    std::fs::read_to_string(path).ok()\n        .map(|s| serde_json::from_str::<serde_json::Value>(&s).is_ok())\n        .unwrap_or(false)\n}","typeGuard":"fn parse_json(text: &str) -> Option<serde_json::Value> {\n    serde_json::from_str(text).ok()\n}","tryCatchPattern":"match discover(&path) {\n    Err(e) if e.to_string().contains(\"not valid JSON\") => {\n        eprintln!(\"source file is not strict JSON; strip comments/trailing commas first\");\n    }\n    r => r?,\n}","preventionTips":["Run jq . source.json on every file before importing","Convert JSONC configs to strict JSON (strip comments/trailing commas) before discovery","Verify the path points at the actual config, not a lockfile, log, or HTML page","Regenerate exports from the source tool rather than hand-copying them"],"tags":["mcp","import","json"],"backgroundTag":"json-parse-error","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}