{"record":{"id":"809a93e8b2b63d2b","repo":"valyala/fasthttp","slug":"unexpected-trailing-char-found-expecting-0-9","errorCode":null,"errorMessage":"unexpected trailing char found: expecting 0-9","messagePattern":"unexpected trailing char found: expecting 0-9","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"bytesconv.go","lineNumber":278,"sourceCode":"\n// ParseUint parses uint from buf.\n//\n// A value too large for an int is an error rather than a wrapped result, so\n// ParseUint accepts exactly the unsigned decimal strings whose value fits in an\n// int on the current platform.\nfunc ParseUint(buf []byte) (int, error) {\n\tv, n, err := parseUintBuf(buf)\n\tif n != len(buf) {\n\t\treturn -1, errUnexpectedTrailingChar\n\t}\n\treturn v, err\n}\n\nvar (\n\terrEmptyInt               = errors.New(\"empty integer\")\n\terrIPv4PartTooLarge       = errors.New(\"ip part cannot exceed 255\")\n\terrUnexpectedFirstChar    = errors.New(\"unexpected first char found: expecting 0-9\")\n\terrUnexpectedTrailingChar = errors.New(\"unexpected trailing char found: expecting 0-9\")\n\terrTooLongInt             = errors.New(\"too long int\")\n)\n\nconst (\n\t// maxIntDiv10 is the largest accumulator that can still take another digit.\n\t// Anything above it overflows an int when multiplied by 10.\n\tmaxIntDiv10 = math.MaxInt / 10\n\n\t// maxSafeIntDigits is how many leading decimal digits can never overflow an\n\t// int, whatever the word size: 10**18-1 fits a 64-bit int and 10**9-1 fits a\n\t// 32-bit one. Go defines strconv.IntSize as 32 or 64 and nothing else.\n\t// TestMaxSafeIntDigits checks both halves of that claim on the build's own\n\t// int size.\n\tmaxSafeIntDigits = 9 * (strconv.IntSize / 32)\n)\n\nfunc parseUintBuf(b []byte) (int, int, error) {\n\tif len(b) == 0 {","sourceCodeStart":260,"sourceCodeEnd":296,"githubUrl":"https://github.com/valyala/fasthttp/blob/c96f600972c6f4a7a30d664257b340ebe9d60124/bytesconv.go#L260-L296","documentation":"errUnexpectedTrailingChar is returned by ParseUint and parseIPv4Octet when digits are followed by a non-digit character. ParseUint consumes all input and requires it to be entirely numeric, so values like \"12x\" or \"1.5\" fail with this error. It signals malformed numeric input with trailing garbage.","triggerScenarios":"ParseUint([]byte(\"8080/tcp\")) (EXPOSE-style values), ParseUint([]byte(\"1.5\")) (float passed to int parser), ParseIPv4 with a component like \"1a.2.3.4\"; also Args.GetUint where the value has trailing characters.","commonSituations":"Float values sent to integer parsers; values with units ('100ms', '5kb'); header values with inline comments or ports; form fields where clients append stray characters.","solutions":["Validate the whole string is digits (e.g. bytes.IndexFunc(buf, nonDigit) < 0) before parsing.","Use strconv.ParseFloat / ParseInt directly if the input legitimately contains decimals or signs — fasthttp's ParseUint is deliberately strict.","Split the input on the expected delimiter first (e.g. cut the port off 'host:port') and parse only the numeric part.","Return 400 for client-supplied values since this is malformed user input, not a server fault."],"exampleFix":"// before\nn, err := fasthttp.ParseUint([]byte(\"1.5\"))\n// after\nf, err := strconv.ParseFloat(\"1.5\", 64) // floats need a float parser\n// or, for strict uint:\nif !isAllDigits(buf) { return 0, errors.New(\"expected unsigned integer\") }\nn, err := fasthttp.ParseUint(buf)","handlingStrategy":"validation","validationCode":"func parseUintStrict(b []byte) (int, error) {\n    if !digitsOnly(b) {\n        return 0, fmt.Errorf(\"trailing characters in %q\", b)\n    }\n    return fasthttp.ParseUint(b)\n}\nfunc digitsOnly(b []byte) bool {\n    return len(b) > 0 && bytes.IndexFunc(b, func(r rune) bool { return r < '0' || r > '9' }) < 0\n}","typeGuard":"func isAllDigits(b []byte) bool {\n    return len(b) > 0 && bytes.IndexFunc(b, func(r rune) bool { return r < '0' || r > '9' }) < 0\n}","tryCatchPattern":"n, err := fasthttp.ParseUint(b)\nif err != nil && err.Error() == \"unexpected trailing char found: expecting 0-9\" {\n    return 0, fmt.Errorf(\"%q must be a plain integer\", b)\n}","preventionTips":["Split compound values ('host:port', '8080/tcp') before parsing","Use float parsers for decimal input","Strip units/suffixes from config values before parsing","Return 400 for malformed client-supplied numbers"],"tags":["integer-parsing","input-validation","trailing-characters"],"backgroundTag":"non-numeric-input","analyzedSha":"c96f600972c6f4a7a30d664257b340ebe9d60124","analyzedAt":"2026-08-31T22:48:28.265Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}