{"record":{"id":"5b62ff6a77547ab4","repo":"lbjlaq/Antigravity-Manager","slug":"jsonc-normalization-preserves-utf-8","errorCode":null,"errorMessage":"JSONC normalization preserves UTF-8","messagePattern":"JSONC normalization preserves UTF-8","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/src/proxy/opencode_sync.rs","lineNumber":401,"sourceCode":"                }\n            }\n            b'/' if i + 1 < bytes.len() && bytes[i + 1] == b'*' => {\n                // Block comment: skip until closing */.\n                i += 2;\n                while i + 1 < bytes.len() && !(bytes[i] == b'*' && bytes[i + 1] == b'/') {\n                    i += 1;\n                }\n                i = (i + 2).min(bytes.len());\n            }\n            _ => {\n                out.push(c);\n                i += 1;\n            }\n        }\n    }\n\n    // Only ASCII syntax is removed; all UTF-8 string bytes remain intact.\n    String::from_utf8(out).expect(\"JSONC normalization preserves UTF-8\")\n}\n\n/// Remove trailing commas (a `,` followed, after optional whitespace, by a closing\n/// `}` or `]`) so `serde_json` can parse JSONC that permits them. Like the comment\n/// stripper, this respects string literals so a comma at the end of a string value is\n/// never touched.\nfn strip_jsonc_trailing_commas(input: &str) -> String {\n    let bytes = input.as_bytes();\n    let mut out = Vec::with_capacity(input.len());\n    let mut i = 0;\n    let mut in_string = false;\n\n    while i < bytes.len() {\n        let c = bytes[i];\n\n        if in_string {\n            out.push(c);\n            if c == b'\\\\' && i + 1 < bytes.len() {","sourceCodeStart":383,"sourceCodeEnd":419,"githubUrl":"https://github.com/lbjlaq/Antigravity-Manager/blob/90a2b6b20797e2e593a83d0c54ab86037863fe70/src-tauri/src/proxy/opencode_sync.rs#L383-L419","documentation":"strip_jsonc_comments removes // and /* */ comments from JSONC while preserving string literals, then converts the byte buffer back to String. The expect asserts the remaining bytes are valid UTF-8; this can only fail if the slicing logic corrupted a multi-byte character boundary.","triggerScenarios":"Parsing an OpenCode config whose bytes are not valid UTF-8 after comment stripping — realistically a bug in index arithmetic cutting into a multi-byte UTF-8 sequence, or input read as lossy/invalid bytes.","commonSituations":"Config file saved with an encoding that produces invalid UTF-8 (e.g. partially decoded bytes); a regression in the stripper's byte offsets when scanning string contents.","solutions":["Ensure the config file is valid UTF-8 (re-save with UTF-8 encoding)","If it reproduces on valid UTF-8 input, fix the byte-index arithmetic in strip_jsonc_comments so multi-byte chars inside strings are pushed verbatim","Use String::from_utf8_lossy as a defensive fallback while debugging"],"exampleFix":"// before\nString::from_utf8(out).expect(\"JSONC normalization preserves UTF-8\")\n// after\nString::from_utf8(out).unwrap_or_else(|e| String::from_utf8_lossy(e.as_bytes()).into_owned())","handlingStrategy":"validation","validationCode":"if let Err(bad) = std::str::from_utf8(&input_bytes) { return Err(format!(\"config not UTF-8 at byte {}\", bad.valid_up_to())); }","typeGuard":null,"tryCatchPattern":"String::from_utf8(out).map_err(|e| anyhow::anyhow!(\"jsonc output not UTF-8: {}\", e))?","preventionTips":["Read config files with strict UTF-8 validation before parsing","Add round-trip tests with multi-byte characters in strings","Track byte indices on char boundaries, not raw u8 increments"],"tags":["rust","utf-8","jsonc","encoding"],"backgroundTag":"invalid-encoding","analyzedSha":"90a2b6b20797e2e593a83d0c54ab86037863fe70","analyzedAt":"2026-09-19T08:34:01.322Z","contentChangedAt":"2026-09-19T08:34:01.322Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}