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

  1. Check disk space: df -h on the kopia cache directory
  2. Fix permissions on the cache/state directory: chown -R $(id -u) "$KOPIA_CACHE_DIRECTORY"
  3. Point KOPIA_CACHE_DIRECTORY at a writable location
  4. 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

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


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)