kopia/kopia · warning
error writing update state
Error message
error writing update state
What it means
After encoding, writeUpdateState persists the buffer atomically via atomicfile.Write to the update state file (under the kopia cache/logs directory). A write failure is wrapped as 'error writing update state'. This indicates the update-state file could not be created/replaced on disk.
Solutions
- Check disk space: df -h on the kopia cache directory
- Fix permissions on the cache/state directory: chown -R $(id -u) "$KOPIA_CACHE_DIRECTORY"
- Point KOPIA_CACHE_DIRECTORY at a writable location
- Disable update checks (KOPIA_CHECK_FOR_UPDATES=false) to bypass state writing
Example fix
// before KOPIA_CACHE_DIRECTORY=/proc/cache kopia repository connect ... // after KOPIA_CACHE_DIRECTORY="$HOME/.cache/kopia" kopia repository connect ...
Defensive patterns
Strategy: try-catch
Validate before calling
if err := os.MkdirAll(stateDir, 0o700); err != nil {
log.Printf("state dir %s not writable: %v", stateDir, err)
}
if st, err := os.Stat(stateDir); err == nil && st.Mode().Perm()&0o200 == 0 {
log.Printf("state dir %s is read-only", stateDir)
} Type guard
func dirWritable(dir string) bool {
f, err := os.CreateTemp(dir, ".wtest")
if err != nil { return false }
os.Remove(f.Name()); f.Close()
return true
} Try / catch
if err := writeUpdateState(us); err != nil {
if strings.Contains(err.Error(), "error writing update state") {
log.Printf("cannot persist update state (disk full or read-only FS): %v", err)
}
} Prevention
- Point KOPIA_CACHE_DIRECTORY at a writable path before running kopia
- Monitor disk space on the cache volume
- Set KOPIA_CHECK_FOR_UPDATES=false in read-only container environments
- Ensure the process user owns the cache/state directory
When it happens
Trigger: atomicfile.Write failing because the state directory is missing, read-only, or lacks permissions — triggered from maybeInitializeUpdateCheck, maybeCheckForUpdates, or maybeCheckGithub on startup or shutdown.
Common situations: Read-only container filesystems; full disks; KOPIA_CACHE_DIRECTORY pointing at a path owned by another user; AppArmor/SELinux denials; state file locked by a stale process on NFS.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- unable to open update state file
- error opening private key file
- error opening root-ca-pem-path
- error removing cache directory
- error saving format blob
AI-assisted analysis of kopia/kopia@82495e54b5 (2026-09-07).
Data as JSON: /api/errors/a62b13ef0e5b3550.
Report an issue: GitHub.
Appendix: source
Thrown at cli/update_check.go:63
NextCheckTime time.Time `json:"nextCheckTimestamp"`
NextNotifyTime time.Time `json:"nextNotifyTimestamp"`
AvailableVersion string `json:"availableVersion"`
}
// updateStateFilename returns the name of the update state.
func (c *App) updateStateFilename() string {
return c.repositoryConfigFileName() + ".update-info.json"
}
// writeUpdateState writes update state file.
func (c *App) writeUpdateState(us *updateState) error {
var buf bytes.Buffer
if err := json.NewEncoder(&buf).Encode(us); err != nil {
return errors.Wrap(err, "unable to marshal JSON")
}
return errors.Wrap(atomicfile.Write(c.updateStateFilename(), &buf), "error writing update state")
}
func (c *App) removeUpdateState() {
os.Remove(c.updateStateFilename()) //nolint:errcheck
}
// getUpdateState reads the update state file if available.
func (c *App) getUpdateState() (*updateState, error) {
f, err := os.Open(c.updateStateFilename())
if err != nil {
return nil, errors.Wrap(err, "unable to open update state file")
}
defer f.Close() //nolint:errcheck
us := &updateState{}
if err := json.NewDecoder(f).Decode(us); err != nil {
return nil, errors.Wrap(err, "unable to parse update state")
}View on GitHub (pinned to 82495e54b5)