{"record":{"id":"ac02657e6374006a","repo":"vitessio/vitess","slug":"invalid-escape-character-q-in-json-string","errorCode":null,"errorMessage":"invalid escape character %q in JSON string","messagePattern":"invalid escape character %q in JSON string","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/mysql/json/marshal.go","lineNumber":465,"sourceCode":"\t\t\t\tif i+6 <= len(src) && src[i] == '\\\\' && src[i+1] == 'u' {\n\t\t\t\t\tr2 := parseHex4(src[i+2 : i+6])\n\t\t\t\t\tif r2 >= 0 {\n\t\t\t\t\t\tcombined := utf16.DecodeRune(r, r2)\n\t\t\t\t\t\tif combined != utf8.RuneError {\n\t\t\t\t\t\t\tdst = utf8.AppendRune(dst, combined)\n\t\t\t\t\t\t\ti += 6\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Lone surrogate: encode as replacement character.\n\t\t\t\tdst = utf8.AppendRune(dst, utf8.RuneError)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tdst = utf8.AppendRune(dst, r)\n\t\tdefault:\n\t\t\treturn dst, fmt.Errorf(\"invalid escape character %q in JSON string\", src[i])\n\t\t}\n\t}\n\treturn dst, nil\n}\n\n// parseHex4 parses exactly 4 hex digits into a rune. Returns -1 on error.\nfunc parseHex4(s []byte) rune {\n\tvar r rune\n\tfor _, ch := range s {\n\t\tr <<= 4\n\t\tswitch {\n\t\tcase ch >= '0' && ch <= '9':\n\t\t\tr |= rune(ch - '0')\n\t\tcase ch >= 'a' && ch <= 'f':\n\t\t\tr |= rune(ch - 'a' + 10)\n\t\tcase ch >= 'A' && ch <= 'F':\n\t\t\tr |= rune(ch - 'A' + 10)\n\t\tdefault:","sourceCodeStart":447,"sourceCodeEnd":483,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/mysql/json/marshal.go#L447-L483","documentation":"JSON only permits the escape characters \\\\ b f n r t u after a backslash inside a string. When unescapeJSON encounters a backslash followed by any other character, it refuses to guess and returns this error. This indicates the string was not produced by a conforming JSON encoder or has been corrupted, since silently passing the byte through could change meaning in the generated SQL.","triggerScenarios":"Serializing a JSON string value or object key containing an escape like \\\\q, \\\\', \\\\x41, \\\\0, or a Windows path written as \\\\Users\\\\name inside a JSON literal that was hand-built or produced by a non-JSON escaper. Reached via writeStringContent -> unescapeJSON, for both top-level strings and object keys.","commonSituations":"Hand-written SQL/JSON literals where backslashes were not doubled per JSON rules; data serialized by a language's native string escaper (e.g. Go strconv.Quote-ish or shell escaping) instead of a JSON encoder; log-processing pipelines that mangle backslashes; config values such as Windows file paths pasted into JSON.","solutions":["Validate with json.Valid/encoding/json before writing so invalid escapes are rejected at the boundary with a familiar error.","Re-encode the data with json.Marshal, which escapes backslashes correctly (\\\\\\\\ for a literal backslash), instead of hand-escaping.","For literal backslashes in paths, escape them (\\\\\\\\) or replace with forward slashes where the consumer allows.","Find and fix the non-JSON escaper in the producer pipeline that is emitting \\\\q-style sequences."],"exampleFix":"// before: unescaped backslashes in a JSON string\ns := `{\"path\": \"C:\\\\temp\\\\file\"}`\n// after: JSON-escaped backslashes (or use json.Marshal)\ns := `{\"path\": \"C:\\\\\\\\temp\\\\\\\\file\"}`","handlingStrategy":"validation","validationCode":"if !json.Valid(input) {\n\treturn errors.New(\"invalid JSON escape sequence in input\")\n}","typeGuard":null,"tryCatchPattern":"if err := writeJSONAsSQL(input); err != nil {\n\tif strings.Contains(err.Error(), \"invalid escape character\") {\n\t\tfixed, merr := reencode(jsonBackslashUnescapeAttempt(raw))\n\t\tif merr == nil {\n\t\t\treturn writeJSONAsSQL(fixed)\n\t\t}\n\t\treturn fmt.Errorf(\"unrecoverable JSON escaping: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Escape JSON strings only via json.Marshal — never custom replacers","Double backslashes when embedding Windows paths in JSON literals","Do not pass strings through non-JSON escapers (shell, strconv) before serialization","Include backslash-heavy payloads in test fixtures"],"tags":["json","escaping","parsing"],"backgroundTag":"invalid-json-escape-sequence","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}