golang/go · critical

Split called after Scan

Error message

Split called after Scan

What it means

`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.

Source

Thrown at src/bufio/scan.go:289

// By default, [Scanner.Scan] uses an internal buffer and sets the
// maximum token size to [MaxScanTokenSize].
//
// Buffer panics if it is called after scanning has started.
func (s *Scanner) Buffer(buf []byte, max int) {
	if s.scanCalled {
		panic("Buffer called after Scan")
	}
	s.buf = buf[0:cap(buf)]
	s.maxTokenSize = max
}

// Split sets the split function for the [Scanner].
// The default split function is [ScanLines].
//
// Split panics if it is called after scanning has started.
func (s *Scanner) Split(split SplitFunc) {
	if s.scanCalled {
		panic("Split called after Scan")
	}
	s.split = split
}

// Split functions

// ScanBytes is a split function for a [Scanner] that returns each byte as a token.
func ScanBytes(data []byte, atEOF bool) (advance int, token []byte, err error) {
	if atEOF && len(data) == 0 {
		return 0, nil, nil
	}
	return 1, data[0:1], nil
}

var errorRune = []byte(string(utf8.RuneError))

// ScanRunes is a split function for a [Scanner] that returns each
// UTF-8-encoded rune as a token. The sequence of runes returned is

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Set the split function once, immediately after constructing the scanner, before `Scan()`.
  2. If you must inspect input to choose a split function, do that peek on a separate reader, then create and configure the scanner.
  3. Centralize scanner construction so lifecycle order is impossible to get wrong.

Example fix

// before
scanner := bufio.NewScanner(r)
scanner.Scan()
scanner.Split(bufio.ScanWords) // panic
// after
scanner := bufio.NewScanner(r)
scanner.Split(bufio.ScanWords)
for scanner.Scan() { ... }
Defensive patterns

Strategy: validation

Validate before calling

scanner := bufio.NewScanner(r)
scanner.Split(bufio.ScanWords) // before any Scan

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/4c3ae9ebd71631d9. Report an issue: GitHub.