{"record":{"id":"65ac14823a15f129","repo":"vitessio/vitess","slug":"unescapeid-err-invalid-input-identifier-s","errorCode":null,"errorMessage":"UnescapeID err: invalid input identifier '%s'","messagePattern":"UnescapeID err: invalid input identifier '(.+?)'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/sqlescape/ids.go","lineNumber":62,"sourceCode":"\t}\n\tbuf.WriteByte('`')\n}\n\n// EscapeIDs runs sqlescape.EscapeID() for all entries in the slice.\nfunc EscapeIDs(identifiers []string) []string {\n\tresult := make([]string, len(identifiers))\n\tfor i := range identifiers {\n\t\tresult[i] = EscapeID(identifiers[i])\n\t}\n\treturn result\n}\n\n// UnescapeID reverses any backticking in the input string by EscapeID.\nfunc UnescapeID(in string) (string, error) {\n\tl := len(in)\n\n\tif l == 0 || in == \"``\" {\n\t\treturn \"\", fmt.Errorf(\"UnescapeID err: invalid input identifier '%s'\", in)\n\t}\n\n\tif l == 1 {\n\t\tif in[0] == '`' {\n\t\t\treturn \"\", errors.New(\"UnescapeID err: invalid input identifier '`'\")\n\t\t}\n\t\treturn in, nil\n\t}\n\n\tfirst, last := in[0], in[l-1]\n\n\tif first == '`' && last != '`' {\n\t\treturn \"\", fmt.Errorf(\"UnescapeID err: unexpected single backtick at position %d in '%s'\", 0, in)\n\t}\n\tif first != '`' && last == '`' {\n\t\treturn \"\", fmt.Errorf(\"UnescapeID err: unexpected single backtick at position %d in '%s'\", l, in)\n\t}\n\tif first != '`' && last != '`' {","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/sqlescape/ids.go#L44-L80","documentation":"UnescapeID reverses backticking done by EscapeID. It throws for input that can never be a valid escaped identifier: an empty string or the literal '``' (empty quoted identifier), which the unescaper refuses to interpret.","triggerScenarios":"Calling UnescapeID(\"\") or UnescapeID(\"``\") — e.g. passing an empty table/column name, or an identifier that escaped to empty because the original name was empty.","commonSituations":"Empty identifiers coming from empty config values, missing metadata, or a caller that escaped an empty string and later unescapes it round-trip.","solutions":["Check for empty input before calling UnescapeID and return a clear caller-level error","Fix the upstream code that produced an empty/empty-escaped identifier","If empty identifiers are legitimate, handle them as a special case before unescaping"],"exampleFix":"// before\nname, err := sqlescape.UnescapeID(id)\n// after\nif id == \"\" || id == \"``\" {\n\treturn fmt.Errorf(\"identifier is empty\")\n}\nname, err := sqlescape.UnescapeID(id)","handlingStrategy":"validation","validationCode":"func safeUnescapeID(in string) (string, error) {\n\tif in == \"\" || in == \"``\" {\n\t\treturn \"\", fmt.Errorf(\"empty identifier\")\n\t}\n\treturn sqlescape.UnescapeID(in)\n}","typeGuard":"func isUnescapableID(in string) bool { return len(in) > 0 && in != \"``\" }","tryCatchPattern":"name, err := sqlescape.UnescapeID(id)\nif err != nil {\n\treturn vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, \"bad identifier %q: %v\", id, err)\n}","preventionTips":["Never allow empty identifiers to flow into escape/unescape round-trips","Validate config-derived names before use","Keep the raw (unescaped) name alongside the escaped one to avoid reverse-unescaping"],"tags":["go","sql","identifier","validation"],"backgroundTag":"invalid-identifier","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}