{"record":{"id":"0c2407ce37c16e27","repo":"golang/go","slug":"final-token","errorCode":null,"errorMessage":"final token","messagePattern":"final token","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"info","filePath":"src/bufio/scan.go","lineNumber":128,"sourceCode":"}\n\n// Text returns the most recent token generated by a call to [Scanner.Scan]\n// as a newly allocated string holding its bytes.\nfunc (s *Scanner) Text() string {\n\treturn string(s.token)\n}\n\n// ErrFinalToken is a special sentinel error value. It is intended to be\n// returned by a Split function to indicate that the scanning should stop\n// with no error. If the token being delivered with this error is not nil,\n// the token is the last token.\n//\n// The value is useful to stop processing early or when it is necessary to\n// deliver a final empty token (which is different from a nil token).\n// One could achieve the same behavior with a custom error value but\n// providing one here is tidier.\n// See the emptyFinalToken example for a use of this value.\nvar ErrFinalToken = errors.New(\"final token\")\n\n// Scan advances the [Scanner] to the next token, which will then be\n// available through the [Scanner.Bytes] or [Scanner.Text] method. It returns false when\n// there are no more tokens, either by reaching the end of the input or an error.\n// After Scan returns false, the [Scanner.Err] method will return any error that\n// occurred during scanning, except that if it was [io.EOF], [Scanner.Err]\n// will return nil.\n// Scan panics if the split function returns too many empty\n// tokens without advancing the input. This is a common error mode for\n// scanners.\nfunc (s *Scanner) Scan() bool {\n\tif s.done {\n\t\treturn false\n\t}\n\ts.scanCalled = true\n\t// Loop until we have a token.\n\tfor {\n\t\t// See if we can get a token with what we already have.","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/bufio/scan.go#L110-L146","documentation":"ErrFinalToken is a sentinel error a SplitFunc returns to tell the Scanner to stop scanning cleanly, optionally delivering one final token (scan.go:128, handled at scan.go:152-159). Despite living among error sentinels, it is not a failure: when the Scanner sees it, it sets done=true, returns the accompanying token (if non-nil) as the last token, and Scanner.Err() reports nil. It exists to enable early termination or to emit a final empty token that a plain nil-token return cannot express.","triggerScenarios":"Triggered only when a SplitFunc deliberately returns ErrFinalToken (scan.go:150-152). Built-in split functions never return it; it is purely an opt-in mechanism for custom splitting logic that knows when to stop before EOF.","commonSituations":"A custom SplitFunc that wants to stop at a sentinel record (e.g., a terminator line) without scanning the rest. Implementations that must deliver a trailing empty token to signal 'end of stream' to downstream consumers. Early-exit parsers for streaming protocols with an explicit end marker.","solutions":["If you are seeing this surface as an unexpected error, you likely returned ErrFinalToken by accident from a SplitFunc — return nil error for normal tokens and reserve ErrFinalToken for explicit stop-with-final-token intent.","To use it intentionally: return (advance, finalTokenBytes, bufio.ErrFinalToken) and the Scanner will deliver finalTokenBytes once and then stop.","To deliver a final empty token specifically, return (0, []byte{}, bufio.ErrFinalToken) — this is the documented use case.","Do not wrap or compare with errors.Is unless you understand it short-circuits Scan; check == directly per the source."],"exampleFix":"// intent: stop after a TERMINATOR line, deliver it as the last token\nsplit := func(data []byte, atEOF bool) (int, []byte, error) {\n    if bytes.HasPrefix(data, []byte(\"TERMINATOR\\n\")) {\n        return len(\"TERMINATOR\\n\"), data[:len(\"TERMINATOR\\n\")], bufio.ErrFinalToken\n    }\n    // normal line splitting otherwise...\n    return ScanLines(data, atEOF)\n}","handlingStrategy":"validation","validationCode":"// Return ErrFinalToken intentionally to stop scanning with an optional final token.\nstopSplit := func(data []byte, atEOF bool) (int, []byte, error) {\n    if /* termination condition */ false {\n        return 0, []byte{}, bufio.ErrFinalToken // deliver a final empty token, then stop\n    }\n    return bufio.ScanLines(data, atEOF)\n}","typeGuard":"// Detect whether a SplitFunc ever returns ErrFinalToken by wrapping it.\nfunc logsFinalToken(split bufio.SplitFunc) bufio.SplitFunc {\n    return func(data []byte, atEOF bool) (int, []byte, error) {\n        adv, tok, err := split(data, atEOF)\n        if err == bufio.ErrFinalToken {\n            log.Println(\"split signalled final token\")\n        }\n        return adv, tok, err\n    }\n}","tryCatchPattern":"// After Scan returns false, Err() reports nil when ErrFinalToken was used.\nfor sc.Scan() {\n    process(sc.Bytes())\n}\nif err := sc.Err(); err != nil {\n    // ErrFinalToken does NOT appear here; the Scanner consumes it as a stop signal\n}","preventionTips":["Treat ErrFinalToken as a control-flow sentinel, not an error — never surface it to users.","Compare with == (the Scanner does), not errors.Is, since it is a precise sentinel.","Only return ErrFinalToken from a SplitFunc when you want a clean stop with an optional final token."],"tags":["go","bufio","scanner","sentinel","control-flow"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}