{"record":{"id":"4c3ae9ebd71631d9","repo":"golang/go","slug":"split-called-after-scan","errorCode":null,"errorMessage":"Split called after Scan","messagePattern":"Split called after Scan","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/bufio/scan.go","lineNumber":289,"sourceCode":"// By default, [Scanner.Scan] uses an internal buffer and sets the\n// maximum token size to [MaxScanTokenSize].\n//\n// Buffer panics if it is called after scanning has started.\nfunc (s *Scanner) Buffer(buf []byte, max int) {\n\tif s.scanCalled {\n\t\tpanic(\"Buffer called after Scan\")\n\t}\n\ts.buf = buf[0:cap(buf)]\n\ts.maxTokenSize = max\n}\n\n// Split sets the split function for the [Scanner].\n// The default split function is [ScanLines].\n//\n// Split panics if it is called after scanning has started.\nfunc (s *Scanner) Split(split SplitFunc) {\n\tif s.scanCalled {\n\t\tpanic(\"Split called after Scan\")\n\t}\n\ts.split = split\n}\n\n// Split functions\n\n// ScanBytes is a split function for a [Scanner] that returns each byte as a token.\nfunc ScanBytes(data []byte, atEOF bool) (advance int, token []byte, err error) {\n\tif atEOF && len(data) == 0 {\n\t\treturn 0, nil, nil\n\t}\n\treturn 1, data[0:1], nil\n}\n\nvar errorRune = []byte(string(utf8.RuneError))\n\n// ScanRunes is a split function for a [Scanner] that returns each\n// UTF-8-encoded rune as a token. The sequence of runes returned is","sourceCodeStart":271,"sourceCodeEnd":307,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/bufio/scan.go#L271-L307","documentation":"`bufio.Scanner.Split(split)` installs a custom split function. Like `Buffer`, it may only be called before scanning starts; doing so after the first `Scan()` panics via the `s.scanCalled` flag. The default split is `ScanLines`; common alternatives are `ScanWords`, `ScanRunes`, `ScanBytes`, or a user function.","triggerScenarios":"Calling `scanner.Split(...)` inside the scan loop or after the first scan; setting the split function conditionally based on the first token (which requires scanning first).","commonSituations":"Switching from line-based to word-based splitting after peeking at the first line; refactors that reorder setup; helpers that reconfigure a scanner passed in from elsewhere.","solutions":["Set the split function once, immediately after constructing the scanner, before `Scan()`.","If you must inspect input to choose a split function, do that peek on a separate reader, then create and configure the scanner.","Centralize scanner construction so lifecycle order is impossible to get wrong."],"exampleFix":"// before\nscanner := bufio.NewScanner(r)\nscanner.Scan()\nscanner.Split(bufio.ScanWords) // panic\n// after\nscanner := bufio.NewScanner(r)\nscanner.Split(bufio.ScanWords)\nfor scanner.Scan() { ... }","handlingStrategy":"validation","validationCode":"scanner := bufio.NewScanner(r)\nscanner.Split(bufio.ScanWords) // before any Scan\n","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set the split function once, right after NewScanner.","Peek on a separate reader if you need input to choose a splitter."],"tags":["bufio","scanner","panic","api-ordering","lifecycle"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}