{"record":{"id":"f9203bc23139fcba","repo":"rqlite/rqlite","slug":"failed-to-read-file-s-w","errorCode":null,"errorMessage":"failed to read file %s: %w","messagePattern":"failed to read file (.+?): %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"auto/file/file.go","lineNumber":90,"sourceCode":"\t\tdir:      dir,\n\t\tname:     name,\n\t\tmetaPath: filepath.Join(dir, \"METADATA.json\"),\n\t}\n\n\tif opt != nil {\n\t\tc.timestamp = opt.Timestamp\n\t}\n\treturn c, nil\n}\n\n// CurrentMetadata returns the current metadata.\nfunc (c *Client) CurrentMetadata(ctx context.Context) (*Metadata, error) {\n\tif !fileExists(c.metaPath) {\n\t\treturn nil, nil\n\t}\n\tdata, err := os.ReadFile(c.metaPath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read file %s: %w\", c.metaPath, err)\n\t}\n\tvar md Metadata\n\tif err := json.Unmarshal(data, &md); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to unmarshal metadata from file %s: %w\", c.metaPath, err)\n\t}\n\treturn &md, nil\n}\n\n// LatestFilePath returns the path to the most recently uploaded file.\nfunc (c *Client) LatestFilePath(ctx context.Context) string {\n\tmd, err := c.CurrentMetadata(ctx)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\tif md == nil {\n\t\treturn \"\"\n\t}\n\treturn md.Name","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/rqlite/rqlite/blob/7586a4d1bdbd9a5a80021664c5a863cd850adb60/auto/file/file.go#L72-L108","documentation":"(*Client).CurrentMetadata reads the JSON metadata file at the client's metaPath and wraps os.ReadFile errors with this message. It is only thrown when the metadata file exists (fileExists check) but cannot be read — i.e. a race, permissions, or I/O problem rather than a missing file.","triggerScenarios":"Calling CurrentMetadata (or CurrentID/LatestFilePath which use it) while the metadata file exists but os.ReadFile fails: permission changed mid-run, file deleted between the exists-check and the read, disk I/O error, or wrong ownership after manual intervention.","commonSituations":"Backup directory permissions tightened by an admin; metadata file removed by a concurrent cleanup job; NFS stale handles; multiple rqlited instances against the same directory with conflicting ownership.","solutions":["Check the wrapped OS error (EACCES, ENOENT, EIO).","Ensure the metadata file is owned/readable by the rqlited user: ls -l <dir>; chown/chmod as needed.","Stop concurrent processes that delete files from the backup directory.","If ENOENT (deleted between check and read), simply retry — CurrentMetadata tolerates a missing file by returning (nil, nil).","Check dmesg/filesystem health on persistent I/O errors."],"exampleFix":"// caller-side resilient pattern\nmd, err := client.CurrentMetadata(ctx)\nif err != nil {\n    if errors.Is(err, fs.ErrNotExist) { md = nil } else { return err }\n}","handlingStrategy":"try-catch","validationCode":"// check readability before use\nif info, err := os.Stat(metaPath); err == nil {\n    if f, err := os.Open(metaPath); err != nil { return err } else { f.Close() }\n    _ = info\n}","typeGuard":null,"tryCatchPattern":"md, err := client.CurrentMetadata(ctx)\nif err != nil {\n    if errors.Is(err, fs.ErrNotExist) {\n        md = nil // raced delete; treat as no metadata\n    } else {\n        return err\n    }\n}","preventionTips":["Keep one writer per backup directory; avoid concurrent cleanup jobs.","Ensure stable ownership/permissions on the metadata file and directory.","Use local (non-NFS) storage where possible to avoid stale-handle EIO errors.","Retry once on transient read errors before failing the backup cycle."],"tags":["filesystem","permissions","io","metadata"],"backgroundTag":"file-read-failed","analyzedSha":"7586a4d1bdbd9a5a80021664c5a863cd850adb60","analyzedAt":"2026-09-03T07:03:02.260Z","contentChangedAt":"2026-09-03T07:03:02.260Z","schemaVersion":2},"datasetVersion":"2026-09-10T12:17:11.382Z"}