{"record":{"id":"09c18428d57f499a","repo":"golang/go","slug":"bytes-reader-seek-invalid-whence","errorCode":null,"errorMessage":"bytes.Reader.Seek: invalid whence","messagePattern":"bytes\\.Reader\\.Seek: invalid whence","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/bytes/reader.go","lineNumber":127,"sourceCode":"\t}\n\tr.i = int64(r.prevRune)\n\tr.prevRune = -1\n\treturn nil\n}\n\n// Seek implements the [io.Seeker] interface.\nfunc (r *Reader) Seek(offset int64, whence int) (int64, error) {\n\tr.prevRune = -1\n\tvar abs int64\n\tswitch whence {\n\tcase io.SeekStart:\n\t\tabs = offset\n\tcase io.SeekCurrent:\n\t\tabs = r.i + offset\n\tcase io.SeekEnd:\n\t\tabs = int64(len(r.s)) + offset\n\tdefault:\n\t\treturn 0, errors.New(\"bytes.Reader.Seek: invalid whence\")\n\t}\n\tif abs < 0 {\n\t\treturn 0, errors.New(\"bytes.Reader.Seek: negative position\")\n\t}\n\tr.i = abs\n\treturn abs, nil\n}\n\n// WriteTo implements the [io.WriterTo] interface.\nfunc (r *Reader) WriteTo(w io.Writer) (n int64, err error) {\n\tr.prevRune = -1\n\tif r.i >= int64(len(r.s)) {\n\t\treturn 0, nil\n\t}\n\tb := r.s[r.i:]\n\tm, err := w.Write(b)\n\tif m > len(b) {\n\t\tpanic(\"bytes.Reader.WriteTo: invalid Write count\")","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/bytes/reader.go#L109-L145","documentation":"bytes.Reader.Seek returns this error when the whence argument is not one of io.SeekStart (0), io.SeekCurrent (1), or io.SeekEnd (2) (reader.go:126-128, the default branch). The whence parameter selects how the offset is interpreted; an unrecognized value has no defined semantics, so the Reader rejects it before touching position. Note Seek clears prevRune regardless.","triggerScenarios":"Triggered by reader.Seek(offset, whence) where whence is any value other than 0, 1, or 2 (reader.go:119-128). Typically a typo'd constant, an uninitialized variable, or a value passed through from an upstream API that uses a different whence convention.","commonSituations":"Passing a raw integer instead of the io.Seek* constant. Mixing OS-level SEEK_SET/SEEK_CUR/SEEK_END constants (which happen to be 0/1/2 but are conceptually different) without mapping. A whence variable that was declared but never assigned (defaults to 0, but computed whence expressions can yield other values).","solutions":["Always use the named constants io.SeekStart, io.SeekCurrent, io.SeekEnd instead of raw 0/1/2.","Validate whence is in {0,1,2} before calling Seek if the value originates from external/untrusted input.","If porting from C-style APIs, map SEEK_SET/CUR/END to the io constants explicitly.","Add a test that asserts Seek is only called with the three valid whence values."],"exampleFix":"// before — raw or wrong whence constant\nr.Seek(10, 3) // invalid whence\n\n// after — use the io constant\nr.Seek(10, io.SeekStart) // or io.SeekCurrent / io.SeekEnd","handlingStrategy":"validation","validationCode":"// Validate whence against the io constants before Seek.\nfunc safeSeek(r *bytes.Reader, off int64, whence int) (int64, error) {\n    switch whence {\n    case io.SeekStart, io.SeekCurrent, io.SeekEnd:\n    default:\n        return 0, fmt.Errorf(\"invalid whence %d\", whence)\n    }\n    return r.Seek(off, whence)\n}","typeGuard":null,"tryCatchPattern":"pos, err := r.Seek(off, whence)\nif err != nil && strings.Contains(err.Error(), \"invalid whence\") {\n    // whence was not 0/1/2; fix the caller\n}","preventionTips":["Always use io.SeekStart, io.SeekCurrent, io.SeekEnd — never raw integers.","Validate whence if it originates from external input.","Map C-style SEEK_* constants to the io package constants when porting."],"tags":["go","bytes","reader","seek","validation"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}