{"record":{"id":"e7050da6134806bd","repo":"vitessio/vitess","slug":"cannot-parse-uint64-from-q","errorCode":null,"errorMessage":"cannot parse uint64 from %q","messagePattern":"cannot parse uint64 from %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/mysql/fastparse/fastparse.go","lineNumber":55,"sourceCode":"// It is equivalent to strconv.ParseUint(s, base, 64) in case it succeeds,\n// but on error it will return the best effort value of what it has parsed so far.\nfunc parseUint64(s string, base int, allowNeg bool) (uint64, error) {\n\tif len(s) == 0 {\n\t\treturn 0, errors.New(\"cannot parse uint64 from empty string\")\n\t}\n\tif base < 2 || base > 36 {\n\t\treturn 0, fmt.Errorf(\"invalid base %d; must be in [2, 36]\", base)\n\t}\n\ti := uint(0)\n\tfor i < uint(len(s)) {\n\t\tif !isSpace(s[i]) {\n\t\t\tbreak\n\t\t}\n\t\ti++\n\t}\n\n\tif i >= uint(len(s)) {\n\t\treturn 0, fmt.Errorf(\"cannot parse uint64 from %q\", s)\n\t}\n\t// For some reason, MySQL parses things as uint64 even with\n\t// a negative sign and then turns it into the 2s complement value.\n\tminus := s[i] == '-'\n\tif minus {\n\t\tif !allowNeg {\n\t\t\treturn 0, fmt.Errorf(\"cannot parse uint64 from %q\", s)\n\t\t}\n\t\ti++\n\t\tif i >= uint(len(s)) {\n\t\t\treturn 0, fmt.Errorf(\"cannot parse uint64 from %q\", s)\n\t\t}\n\t}\n\n\td := uint64(0)\n\tj := i\nnext:\n\tfor i < uint(len(s)) {","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/mysql/fastparse/fastparse.go#L37-L73","documentation":"After skipping leading whitespace, parseUint64 found no parseable characters left (the string was all whitespace, or empty of digits, or only a sign that is not allowed). It returns this error quoting the original string, together with the best-effort value 0.","triggerScenarios":"Calling fastparse.ParseUint64 (allowNeg=false) or ParseUint64WithNeg with strings like \" \", \"\\t\\n\", \"-5\" when negatives are disallowed, \"+\" alone, or any string whose first non-space byte is not a digit (or a '-' when allowNeg is true).","commonSituations":"Parsing empty/blank user input or empty query parameters as numbers; SQL string values like '' or '-' converted to integers in expression evaluation; config values that are unset strings; clients sending non-numeric values where MySQL would coerce to 0 with warnings.","solutions":["Trim and validate the input is a non-empty numeric string before calling ParseUint64.","Treat the returned error as MySQL would: coerce to the returned best-effort 0 value if that matches SQL semantics, or propagate a conversion error to the client.","If negatives are legitimate, use ParseUint64WithNeg (allowNeg=true) so \"-5\" parses as the 2s-complement value.","Handle empty-string input at a higher layer (e.g. return 0 or NULL) instead of routing it to the parser."],"exampleFix":"// before\nv, err := fastparse.ParseUint64(userInput, 10)\n\n// after\ninput := strings.TrimSpace(userInput)\nif input == \"\" {\n    return 0, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, \"empty numeric value\")\n}\nv, err := fastparse.ParseUint64(input, 10)","handlingStrategy":"validation","validationCode":"func isParseableUint(s string, allowNeg bool) bool {\n    s = strings.TrimSpace(s)\n    if s == \"\" {\n        return false\n    }\n    if s[0] == '-' {\n        return allowNeg && len(s) > 1\n    }\n    if s[0] == '+' {\n        s = s[1:]\n    }\n    if s == \"\" {\n        return false\n    }\n    for _, c := range s {\n        if c < '0' || c > '9' {\n            return false\n        }\n    }\n    return true\n}","typeGuard":null,"tryCatchPattern":"v, err := fastparse.ParseUint64(s, 10)\nif err != nil {\n    if strings.Contains(err.Error(), \"cannot parse uint64\") {\n        // match MySQL coercion semantics: use best-effort value 0\n        v = 0\n    }\n}","preventionTips":["Trim whitespace and reject blank strings before parsing.","Use ParseUint64WithNeg when negative values can legitimately appear.","Decide explicitly whether empty input should be 0, NULL, or an error — do it before parsing.","Remember fastparse returns a best-effort value alongside the error; do not use the value without checking err."],"tags":["parsing","fastparse","integer","invalid-input"],"backgroundTag":"invalid-numeric-string","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}