sipeed/picoclaw · error
Failed to save catalogs: %v
Error message
Failed to save catalogs: %v
What it means
Returned by DELETE /api/models/catalog/{id} when saveCatalogs() cannot persist the updated store. saveCatalogs (model_catalog.go:91-98) marshals then calls fileutil.WriteFileAtomic, which writes a temp file in the same directory, fsyncs, chmods 0600, and renames. Failures: temp-file creation (directory permissions, disk full), write/sync errors (disk full, I/O error), or rename failure (Windows file lock by antivirus/indexer, NFS quirks). Because the write is atomic, the original file is untouched when this error fires.
Source
Thrown at web/backend/api/model_catalog.go:165
if id == "" {
http.Error(w, "id is required", http.StatusBadRequest)
return
}
store, err := loadCatalogs()
if err != nil {
http.Error(w, fmt.Sprintf("Failed to load catalogs: %v", err), http.StatusInternalServerError)
return
}
if _, ok := store.Entries[id]; !ok {
http.Error(w, "catalog not found", http.StatusNotFound)
return
}
delete(store.Entries, id)
if err := saveCatalogs(store); err != nil {
http.Error(w, fmt.Sprintf("Failed to save catalogs: %v", err), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
}
View on GitHub (pinned to 49183d7e8d)
Solutions
- Check the wrapped error text - it names the failing stage (create/write/rename)
- Free disk space or expand the volume if full
- Grant the backend user write access to the config home directory
- On Windows, exclude the config directory from real-time AV scanning; on NFS, prefer a local dir
- Retry the DELETE - atomicity guarantees no partial state, so the same id can be re-deleted safely
Defensive patterns
Strategy: retry
Try / catch
for (let attempt = 0; attempt < 2; attempt++) {
const res = await fetch(`/api/models/catalog/${encodeURIComponent(id)}`, {method: 'DELETE'});
if (res.ok || res.status === 404) return; // success or already gone
const text = await res.text();
if (text.startsWith('Failed to save catalogs')) {
// atomic write failed but left the store intact - same delete is safe to retry once
await sleep(800);
continue;
}
throw new Error(text);
} Prevention
- Retry confidently: WriteFileAtomic never leaves a partial model_catalogs.json, so the same DELETE is idempotent
- Keep the config home directory writable and off read-only mounts
- On Windows, exclude the config dir from AV real-time scanning to avoid rename locks
When it happens
Trigger: Disk full on the home/config volume; config.GetHome() directory not writable by the backend user; on Windows, an AV scanner holding the file during rename; NFS/DFS mounts where rename semantics misbehave.
Common situations: Edge devices with small disks filling up; service users missing write permission on the config dir after a security hardening pass; endpoint protection on Windows hosts.
Related errors
- write result: %w
- Failed to save launcher config: %v
- Failed to load catalogs: %v
- create output dir: %w
- failed to save config: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/984f719860dead84.
Report an issue: GitHub.