{"record":{"id":"a62b13ef0e5b3550","repo":"kopia/kopia","slug":"error-writing-update-state","errorCode":null,"errorMessage":"error writing update state","messagePattern":"error writing update state","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"cli/update_check.go","lineNumber":63,"sourceCode":"\tNextCheckTime    time.Time `json:\"nextCheckTimestamp\"`\n\tNextNotifyTime   time.Time `json:\"nextNotifyTimestamp\"`\n\tAvailableVersion string    `json:\"availableVersion\"`\n}\n\n// updateStateFilename returns the name of the update state.\nfunc (c *App) updateStateFilename() string {\n\treturn c.repositoryConfigFileName() + \".update-info.json\"\n}\n\n// writeUpdateState writes update state file.\nfunc (c *App) writeUpdateState(us *updateState) error {\n\tvar buf bytes.Buffer\n\n\tif err := json.NewEncoder(&buf).Encode(us); err != nil {\n\t\treturn errors.Wrap(err, \"unable to marshal JSON\")\n\t}\n\n\treturn errors.Wrap(atomicfile.Write(c.updateStateFilename(), &buf), \"error writing update state\")\n}\n\nfunc (c *App) removeUpdateState() {\n\tos.Remove(c.updateStateFilename()) //nolint:errcheck\n}\n\n// getUpdateState reads the update state file if available.\nfunc (c *App) getUpdateState() (*updateState, error) {\n\tf, err := os.Open(c.updateStateFilename())\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"unable to open update state file\")\n\t}\n\tdefer f.Close() //nolint:errcheck\n\n\tus := &updateState{}\n\tif err := json.NewDecoder(f).Decode(us); err != nil {\n\t\treturn nil, errors.Wrap(err, \"unable to parse update state\")\n\t}","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/kopia/kopia/blob/82495e54b584c1ef6073c9e1be048f57f8aef078/cli/update_check.go#L45-L81","documentation":"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.","triggerScenarios":"atomicfile.Write failing because the state directory is missing, read-only, or lacks permissions — triggered from maybeInitializeUpdateCheck, maybeCheckForUpdates, or maybeCheckGithub on startup or shutdown.","commonSituations":"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.","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"],"exampleFix":"// before\nKOPIA_CACHE_DIRECTORY=/proc/cache kopia repository connect ...\n// after\nKOPIA_CACHE_DIRECTORY=\"$HOME/.cache/kopia\" kopia repository connect ...","handlingStrategy":"try-catch","validationCode":"if err := os.MkdirAll(stateDir, 0o700); err != nil {\n\tlog.Printf(\"state dir %s not writable: %v\", stateDir, err)\n}\nif st, err := os.Stat(stateDir); err == nil && st.Mode().Perm()&0o200 == 0 {\n\tlog.Printf(\"state dir %s is read-only\", stateDir)\n}","typeGuard":"func dirWritable(dir string) bool {\n\tf, err := os.CreateTemp(dir, \".wtest\")\n\tif err != nil { return false }\n\tos.Remove(f.Name()); f.Close()\n\treturn true\n}","tryCatchPattern":"if err := writeUpdateState(us); err != nil {\n\tif strings.Contains(err.Error(), \"error writing update state\") {\n\t\tlog.Printf(\"cannot persist update state (disk full or read-only FS): %v\", err)\n\t}\n}","preventionTips":["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"],"tags":["file","write","cli","update-check","permissions"],"backgroundTag":"file-write-failed","analyzedSha":"82495e54b584c1ef6073c9e1be048f57f8aef078","analyzedAt":"2026-09-07T20:35:21.689Z","contentChangedAt":"2026-09-07T20:35:21.689Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}