thanos-io/thanos · error
scanning file
Error message
scanning file %s
What it means
After scanning all frames, NewLocalStoreFromJSONMmappableFile checks skanner.Err() and wraps any scanner-level I/O failure with "scanning file <path>". This is a low-level read error on the backing file, not a JSON schema issue.
Solutions
- Check file permissions and that the path exists and is readable by the process.
- Verify disk health / mount stability for the backing storage.
- Regenerate the local store file if it was truncated or corrupted.
- Inspect the wrapped inner error for the exact OS-level cause.
Example fix
// before
store, err := NewLocalStoreFromJSONMmappableFile(mmappablePath)
// after
if _, err := os.Stat(mmappablePath); err != nil {
// regenerate dump first
}
store, err := NewLocalStoreFromJSONMmappableFile(mmappablePath) Defensive patterns
Strategy: try-catch
Validate before calling
f, err := os.Open(path)
if err != nil { return err }
if fi, err := f.Stat(); err != nil || fi.Size() == 0 { return errors.New("missing or empty file") } Try / catch
if err != nil {
if os.IsPermission(errors.Unwrap(err)) { /* fix perms */ }
// else regenerate the file and retry load
} Prevention
- Keep dump files on stable local storage, not flaky network mounts
- Ensure file permissions survive container restarts
- Guard cleanup jobs against deleting in-use files
When it happens
Trigger: The mappable file is unreadable mid-scan: disk I/O error, permission change after open, or the file being truncated/deleted while scanning.
Common situations: Files on flaky network mounts (NFS/EFS); permission issues after container restarts; files deleted by cleanup jobs while being loaded.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- remove any existing index at path
- close
- open index reader for block %+v
- open chunk reader for block %+v
- write
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/0f19c39853f656aa.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/store/local.go:107
if series == nil {
level.Warn(logger).Log("msg", "not a valid series", "frame", resp.String())
continue
}
chks := make([]int, 0, len(series.Chunks))
// Sort chunks in separate slice by MinTime for easier lookup. Find global max and min.
for ci := range series.Chunks {
chks = append(chks, ci)
}
sort.Slice(chks, func(i, j int) bool {
return series.Chunks[chks[i]].MinTime < series.Chunks[chks[j]].MinTime
})
s.series = append(s.series, series)
s.sortedChunks = append(s.sortedChunks, chks)
}
if err := skanner.Err(); err != nil {
return nil, errors.Wrapf(err, "scanning file %s", path)
}
level.Info(logger).Log("msg", "loading JSON file succeeded", "file", path, "series", len(s.series))
return s, nil
}
// ScanGRPCCurlProtoStreamMessages allows to tokenize each streamed gRPC message from grpcurl tool.
func ScanGRPCCurlProtoStreamMessages(data []byte, atEOF bool) (advance int, token []byte, err error) {
var delim = []byte(`}
{`)
if atEOF && len(data) == 0 {
return 0, nil, nil
}
if idx := bytes.LastIndex(data, delim); idx != -1 {
return idx + 2, data[:idx+1], nil
}
// If we're at EOF, let's return all.
if atEOF {
return len(data), data, nilView on GitHub (pinned to 35b8b99117)