{"record":{"id":"c6551a0ff43315f1","repo":"github/copilot-sdk","slug":"unescaped-control-character-at-position-pos-1","errorCode":null,"errorMessage":"Unescaped control character at position <pos-1>","messagePattern":"Unescaped control character at position <pos-1>","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"java/sdk/src/main/java/com/github/copilot/tool/CopilotToolProcessor.java","lineNumber":1033,"sourceCode":"            if (c == 't' || c == 'f') {\n                return parseBoolean();\n            }\n            if (c == 'n') {\n                return parseNull();\n            }\n            return parseNumber();\n        }\n\n        private String parseString() {\n            expect('\"');\n            StringBuilder sb = new StringBuilder();\n            while (pos < input.length() && input.charAt(pos) != '\"') {\n                char current = input.charAt(pos++);\n                if (current == '\\\\') {\n                    sb.append(parseEscape());\n                } else {\n                    if (current < 0x20) {\n                        throw new IllegalArgumentException(\"Unescaped control character at position \" + (pos - 1));\n                    }\n                    sb.append(current);\n                }\n            }\n            expect('\"');\n            return sb.toString();\n        }\n\n        private char parseEscape() {\n            if (pos >= input.length()) {\n                throw new IllegalArgumentException(\"Unterminated string escape at position \" + pos);\n            }\n            char escaped = input.charAt(pos++);\n            return switch (escaped) {\n                case '\"', '\\\\', '/' -> escaped;\n                case 'b' -> '\\b';\n                case 'f' -> '\\f';\n                case 'n' -> '\\n';","sourceCodeStart":1015,"sourceCodeEnd":1051,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/java/sdk/src/main/java/com/github/copilot/tool/CopilotToolProcessor.java#L1015-L1051","documentation":"While scanning a JSON string literal, the converter's string parser encountered a character below 0x20 (a raw control character such as newline, tab, or NUL) that was not escaped with a backslash. Strict JSON forbids literal control characters inside strings; they must be written as escapes (\\n, \\t, \\uXXXX, etc.).","triggerScenarios":"Parsing JSON whose string value contains a raw newline, tab, carriage return, or other control char, e.g. '{\"text\":\"line1\nline2\"}' produced by naive string concatenation instead of proper JSON serialization.","commonSituations":"Hand-built JSON via string concatenation with real newlines/tabs inside string values; data copied from logs or terminals embedding control bytes; binary data or terminal escape codes (ANSI color) pasted into JSON strings.","solutions":["Fix the producer to emit escaped control characters (\\n, \\t) or use a real JSON serializer instead of string concatenation","Pre-sanitize the input by replacing raw control chars (c < 0x20) inside strings with their escape sequences before parsing","Locate the reported position to identify which control character leaked in and where it came from","If the payload genuinely contains binary/control data, Base64-encode it inside the JSON string"],"exampleFix":"// before\nString json = \"{\\\"msg\\\":\\\"hello\\nworld\\\"}\"; // raw newline inside string\n// after\nString json = \"{\\\"msg\\\":\\\"hello\\\\nworld\\\"}\"; // escaped \\n","handlingStrategy":"try-catch","validationCode":"for (int i = 0; i < json.length(); i++) {\n    if (json.charAt(i) < 0x20 && json.charAt(i) != '\\n' /* inside strings this is still invalid */) {\n        throw new IllegalArgumentException(\"Raw control character at index \" + i);\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    String result = CopilotToolProcessor.jsonToMapOfSource(json);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"Unescaped control character\")) {\n        // re-serialize the payload with a proper JSON encoder and retry\n    }\n}","preventionTips":["Always build JSON with a serializer, never string concatenation","Base64-encode binary or control-heavy data before embedding in JSON strings","Strip ANSI/terminal escape codes from data captured from logs","Validate payloads from external sources with a strict JSON parser first"],"tags":["java","json","parsing","encoding"],"backgroundTag":"json-parse-error","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}