{"record":{"id":"a96d8ca82147cba3","repo":"wavetermdev/waveterm","slug":"beginning-of-file","errorCode":null,"errorMessage":"beginning of file","messagePattern":"beginning of file","errorType":"error_code","errorClass":"ErrBOF","httpStatus":null,"severity":"info","filePath":"pkg/util/logview/multibuf.go","lineNumber":20,"sourceCode":"// SPDX-License-Identifier: Apache-2.0\n\npackage logview\n\nimport (\n\t\"errors\"\n\t\"io\"\n\t\"os\"\n)\n\ntype MultiBufferByteGetter struct {\n\tFile    *os.File\n\tOffset  int64\n\tEOF     bool\n\tBuffers [][]byte\n\tBufSize int64\n}\n\nvar ErrBOF = errors.New(\"beginning of file\")\n\nfunc MakeMultiBufferByteGetter(file *os.File, bufSize int64) *MultiBufferByteGetter {\n\treturn &MultiBufferByteGetter{\n\t\tFile:    file,\n\t\tOffset:  0,\n\t\tEOF:     false,\n\t\tBuffers: [][]byte{},\n\t\tBufSize: bufSize,\n\t}\n}\n\nfunc (mb *MultiBufferByteGetter) readFromBuffer(offset int64) (byte, bool) {\n\tif offset < mb.Offset || offset >= mb.Offset+int64(mb.bufSize()) {\n\t\treturn 0, false\n\t}\n\tbufIdx := int((offset - mb.Offset) / mb.BufSize)\n\tbufOffset := (offset - mb.Offset) % mb.BufSize\n\treturn mb.Buffers[bufIdx][bufOffset], true","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/util/logview/multibuf.go#L2-L38","documentation":"ErrBOF (\"beginning of file\") is a sentinel error in the logview multibuf package. Backward-scanning APIs (PrevLinePtr, Move, PrevLine) return it when the caller asks to move before offset 0 of the file, i.e. there is no earlier line to read. It is a normal, expected signal — not a failure — that the scan has hit the start of the file.","triggerScenarios":"Calling PrevLinePtr/PrevLine repeatedly until the iterator is already at offset 0, or calling Move with a negative target offset below 0 on a MultiBufferByteGetter reading a log file.","commonSituations":"Tail/grep-style log viewers that page backwards through a log and read past the first line; scanning a small file where the requested lookback window exceeds the file size.","solutions":["Check for errors.Is(err, logview.ErrBOF) after each backward step and treat it as the stop condition of your scan loop, not as a failure.","Clamp or validate the target offset before calling Move/PrevLinePtr so it never goes below 0.","Ensure the *os.File passed to MakeMultiBufferByteGetter is valid and opened for reading so offsets behave as expected."],"exampleFix":"// before\nline, err := mb.PrevLinePtr(off)\nif err != nil {\n    return err\n}\n// after\nline, err := mb.PrevLinePtr(off)\nif errors.Is(err, logview.ErrBOF) {\n    return nil // reached start of file; stop scanning\n}\nif err != nil {\n    return err\n}","handlingStrategy":"try-catch","validationCode":"if targetOffset < 0 {\n    // skip backward scan; already at start of file\n}","typeGuard":"func isBOF(err error) bool { return errors.Is(err, logview.ErrBOF) }","tryCatchPattern":"line, err := mb.PrevLinePtr(off)\nif errors.Is(err, logview.ErrBOF) {\n    return io.EOF // normalize to standard end/edge-of-input signal\n}\nif err != nil {\n    return err\n}","preventionTips":["Always treat ErrBOF as a loop-termination signal when scanning backwards.","Clamp offsets to [0, fileSize) before calling Move/PrevLinePtr.","Use errors.Is, never ==, for sentinel comparison."],"tags":["go","file-io","sentinel-error","log-parsing"],"backgroundTag":"beginning-of-file-sentinel","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}