{"record":{"id":"dbae1c4d57e36e14","repo":"vitessio/vitess","slug":"reading-json-object-key-w","errorCode":null,"errorMessage":"reading JSON object key: %w","messagePattern":"reading JSON object key: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/mysql/json/marshal.go","lineNumber":290,"sourceCode":"\t\t\treturn nil\n\t\t}\n\t\tif !first {\n\t\t\tif w.data[w.pos] != ',' {\n\t\t\t\treturn fmt.Errorf(\"expected ',' or '}' in object, got %q\", w.data[w.pos])\n\t\t\t}\n\t\t\tw.pos++\n\t\t\tw.buf.WriteString(\", \")\n\t\t\tw.skipWhitespace()\n\t\t}\n\t\tfirst = false\n\n\t\t// Key (always a string).\n\t\tif w.pos >= len(w.data) || w.data[w.pos] != '\"' {\n\t\t\treturn errors.New(\"expected string key in JSON object\")\n\t\t}\n\t\tw.buf.WriteString(\"_utf8mb4\")\n\t\tif err := w.writeStringContent(); err != nil {\n\t\t\treturn fmt.Errorf(\"reading JSON object key: %w\", err)\n\t\t}\n\t\tw.buf.WriteString(\", \")\n\n\t\t// Colon separator.\n\t\tw.skipWhitespace()\n\t\tif w.pos >= len(w.data) || w.data[w.pos] != ':' {\n\t\t\treturn errors.New(\"expected ':' after object key\")\n\t\t}\n\t\tw.pos++\n\n\t\t// Value.\n\t\tif err := w.writeValue(false, depth+1); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n\nfunc (w *sqlWriter) writeArray(depth int) error {","sourceCodeStart":272,"sourceCodeEnd":308,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/mysql/json/marshal.go#L272-L308","documentation":"This error wraps a failure that occurred while reading the string key of a JSON object during conversion of a raw JSON document into a MySQL SQL expression (JSON_OBJECT). The writeObject parser requires every object key to be a double-quoted JSON string, and writeStringContent (which reads and SQL-encodes that key) returned an error — e.g. the key string is unterminated, or contains a malformed escape sequence. The wrapper adds context so the caller knows the failure happened in the key portion of an object rather than in a value.","triggerScenarios":"Calling the JSON-to-SQL writer (sqlWriter/writeValue path, e.g. via marshaling a JSON column value into JSON_OBJECT(...) SQL) with a document whose object key string is malformed: an unterminated key string (no closing quote before end of input), a key containing an invalid escape character (e.g. {\"a\\q\": 1}), or a key with a truncated/invalid \\u escape (e.g. {\"\\u12\": 1}). Also triggered when the key string is truncated by a length-limited or corrupt input buffer.","commonSituations":"Applications storing hand-built JSON strings in a Vitess/MySQL JSON column where the JSON was assembled by string concatenation instead of a JSON encoder; corrupted JSON payloads arriving over the wire or read from a damaged binlog/audit log; truncation of a large JSON document by an intermediate layer (column size limits, log line cuts) leaving a key string open.","solutions":["Validate the JSON with encoding/json Unmarshal (or json.Valid) before passing it to the writer, so malformed keys are rejected with a standard parser error.","Locate the object key at the reported position and fix or re-encode the JSON with a proper encoder (json.Marshal), which guarantees well-formed key strings and escapes.","If input comes from an untrusted/external source, check for truncation (complete document received) and reject payloads that fail json.Valid with a clear client-side error.","If the invalid escape comes from double-escaping (e.g. \\\"\\\\\\\\q\\\" produced by string escaping in another layer), remove the extra escaping layer in the producer."],"exampleFix":"// before: hand-built JSON with invalid escape\npayload := fmt.Sprintf(`{\"na\\\\qme\": %d}`, id)\n// after: build JSON with the encoder\nb, _ := json.Marshal(map[string]int{\"name\": id})","handlingStrategy":"validation","validationCode":"if !json.Valid(input) {\n\treturn fmt.Errorf(\"invalid JSON document: object key not readable\")\n}","typeGuard":null,"tryCatchPattern":"if err := writeJSONAsSQL(input); err != nil {\n\tvar pe *json.SyntaxError\n\tif errors.As(err, nil) || strings.Contains(err.Error(), \"reading JSON object key\") {\n\t\t// fall back: reject or re-encode the document\n\t\treturn handleInvalidJSON(input, err)\n\t}\n\treturn err\n}","preventionTips":["Always produce JSON with json.Marshal/Encoder, never string concatenation","Run json.Valid on untrusted input before conversion","Guard against truncation: verify payload length/completeness before parsing","Add a unit test with escaped characters in object keys"],"tags":["json","parsing","escaping","mysql"],"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"}