github/copilot-sdk · error · IllegalArgumentException

Unterminated string escape at position

Error message

Unterminated string escape at position <pos>

What it means

parseEscape is invoked after a backslash inside a JSON string, but the input has already ended — the backslash was the last character, so no escape character follows. This means the string literal is truncated/malformed, and the converter reports the position of the dangling escape.

Solutions

  1. Escape backslashes properly: every literal \ in a JSON string must be written as \\ (so a path ending in \ becomes ...\\\\)
  2. Use a JSON serializer to build the string instead of manual escaping
  3. Check whether the payload was truncated in transit or by logging; re-fetch the complete payload
  4. Fix any hand-rolled escaping/unescape code that strips one backslash too many

Example fix

// before
String json = "{\"path\":\"C:\\tmp\\\"}"; // trailing single backslash
// after
String json = "{\"path\":\"C:\\tmp\\\"}".replace("\\\\\"", "\\\\\\\\\"");
// better: serialize with a JSON library
String json = new JSONObject().put("path", "C:\tmp\\").toString();
Defensive patterns

Strategy: validation

Validate before calling

if (json.trim().endsWith("\\")) {
    throw new IllegalArgumentException("Payload ends with a dangling backslash; escaping is broken or input truncated");
}

Try / catch

try {
    String result = CopilotToolProcessor.jsonToMapOfSource(json);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("Unterminated string escape")) {
        // check payload completeness / re-encode backslashes
    }
}

Prevention

When it happens

Trigger: A JSON string ending in a lone backslash, e.g. '{"path":"C:\\' where the final backslash is not itself escaped (should be '\\\\'), or a truncated string from a cut-off network payload.

Common situations: Windows file paths embedded in JSON where backslashes were not doubled; manually escaped strings where the trailing backslash was missed; truncated responses from a flaky stream or log capture.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09). Data as JSON: /api/errors/73f263b4df2b2a24. Report an issue: GitHub.

Appendix: source

Thrown at java/sdk/src/main/java/com/github/copilot/tool/CopilotToolProcessor.java:1044

            StringBuilder sb = new StringBuilder();
            while (pos < input.length() && input.charAt(pos) != '"') {
                char current = input.charAt(pos++);
                if (current == '\\') {
                    sb.append(parseEscape());
                } else {
                    if (current < 0x20) {
                        throw new IllegalArgumentException("Unescaped control character at position " + (pos - 1));
                    }
                    sb.append(current);
                }
            }
            expect('"');
            return sb.toString();
        }

        private char parseEscape() {
            if (pos >= input.length()) {
                throw new IllegalArgumentException("Unterminated string escape at position " + pos);
            }
            char escaped = input.charAt(pos++);
            return switch (escaped) {
                case '"', '\\', '/' -> escaped;
                case 'b' -> '\b';
                case 'f' -> '\f';
                case 'n' -> '\n';
                case 'r' -> '\r';
                case 't' -> '\t';
                case 'u' -> parseUnicodeEscape();
                default -> throw new IllegalArgumentException(
                        "Invalid escape sequence \\" + escaped + " at position " + (pos - 2));
            };
        }

        private char parseUnicodeEscape() {
            if (pos + 4 > input.length()) {
                throw new IllegalArgumentException("Incomplete Unicode escape at position " + (pos - 2));

View on GitHub (pinned to cd8cf15dc3)