{"record":{"id":"e34969003cf216bc","repo":"gastownhall/beads","slug":"failed-to-read-backup-state-w","errorCode":null,"errorMessage":"failed to read backup state: %w","messagePattern":"failed to read backup state: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/backup_export.go","lineNumber":64,"sourceCode":"\tif beadsDir == \"\" {\n\t\treturn \"\", fmt.Errorf(\"%s; %s\", activeWorkspaceNotFoundError(), diagHint())\n\t}\n\tdir := filepath.Join(beadsDir, \"backup\")\n\tif err := os.MkdirAll(dir, 0700); err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to create backup directory: %w\", err)\n\t}\n\treturn dir, nil\n}\n\n// loadBackupState reads the backup state file, returning a zero state if missing.\nfunc loadBackupState(dir string) (*backupState, error) {\n\tpath := filepath.Join(dir, \"backup_state.json\")\n\tdata, err := os.ReadFile(path) //nolint:gosec // path is constructed internally\n\tif os.IsNotExist(err) {\n\t\treturn &backupState{}, nil\n\t}\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read backup state: %w\", err)\n\t}\n\tvar state backupState\n\tif err := json.Unmarshal(data, &state); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse backup state: %w\", err)\n\t}\n\treturn &state, nil\n}\n\n// saveBackupState writes the backup state file atomically.\nfunc saveBackupState(dir string, state *backupState) error {\n\tdata, err := json.MarshalIndent(state, \"\", \"  \")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to marshal backup state: %w\", err)\n\t}\n\treturn atomicWriteFile(filepath.Join(dir, \"backup_state.json\"), data)\n}\n\n// atomicWriteFile writes data to a same-directory temp file, fsyncs the","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/backup_export.go#L46-L82","documentation":"loadBackupState in cmd/bd/backup_export.go reads .beads/backup_state.json to decide whether an auto-backup is due. This error wraps any os.ReadFile failure that is NOT a missing file (a missing file is treated as a fresh empty state). It means the state file exists but could not be read (permissions, I/O error, path is a directory).","triggerScenarios":"os.ReadFile(backup_state.json) fails with an error where os.IsNotExist(err) is false: e.g. permission denied, EIO, or the path is a directory named backup_state.json.","commonSituations":"Running bd as a different user than the one that created the state file (root vs user); read-only or corrupted filesystem; a directory accidentally created at .beads/backup_state.json; NFS/disk errors.","solutions":["Check file permissions: ls -l .beads/backup_state.json and chmod/chown so the running user can read it.","If the file is a directory or unreadable junk, remove it: rm -f .beads/backup_state.json (bd recreates it on the next backup).","Verify the .beads directory and filesystem are writable and healthy (df, dmesg for I/O errors).","Re-run the command; if it persists, run as the user who owns the beads workspace instead of root/sudo."],"exampleFix":"// before (shell)\nsudo bd sync\n// after\nbd sync  # run as the workspace owner so .beads/backup_state.json stays readable/writable by the same user","handlingStrategy":"fallback","validationCode":"const p = '.beads/backup_state.json'\nif st, err := os.Stat(p); err == nil && st.IsDir() {\n    os.RemoveAll(p) // directory where a file is expected\n}\n// ensure readable\nf, err := os.OpenFile(p, os.O_RDONLY, 0)\nif err == nil { f.Close() }","typeGuard":"func isPermissionErr(err error) bool {\n    var pe *fs.PathError\n    return errors.As(err, &pe) && errors.Is(pe.Err, fs.ErrPermission)\n}","tryCatchPattern":"state, err := loadBackupState(dir)\nif err != nil {\n    var pe *fs.PathError\n    if errors.As(err, &pe) && (errors.Is(pe.Err, fs.ErrPermission) || errors.Is(pe.Err, syscall.EIO)) {\n        log.Printf(\"backup state unreadable, starting fresh: %v\", err)\n        state = &backupState{}\n    } else {\n        return err\n    }\n}","preventionTips":["Run all bd commands as the same user that owns the workspace","Never create files/dirs named like bd's internal state files in .beads","Monitor filesystem health if .beads lives on network storage"],"tags":["go","filesystem","io","backup"],"backgroundTag":"file-read-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}