sipeed/picoclaw · error
failed to delete credential: %v
Error message
failed to delete credential: %v
What it means
Returned as HTTP 500 by POST /api/oauth/logout when oauthDeleteCredential fails. That function loads the on-disk credential store, deletes the provider's entry, and saves the store; failure means LoadStore or SaveStore errored — typically a corrupt/unreadable credentials file or a filesystem problem (permissions, read-only mount, disk full). Note the implication: if the store file itself is broken, you cannot log out through the API because logout must rewrite that same file.
Source
Thrown at web/backend/api/oauth.go:478
}
defer r.Body.Close()
var req struct {
Provider string `json:"provider"`
}
if err = json.Unmarshal(body, &req); err != nil {
http.Error(w, fmt.Sprintf("invalid JSON: %v", err), http.StatusBadRequest)
return
}
provider, err := normalizeOAuthProvider(req.Provider)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if err := oauthDeleteCredential(provider); err != nil {
http.Error(w, fmt.Sprintf("failed to delete credential: %v", err), http.StatusInternalServerError)
return
}
if err := h.syncProviderAuthMethod(provider, ""); err != nil {
http.Error(w, fmt.Sprintf("failed to update config: %v", err), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]any{
"status": "ok",
"provider": provider,
})
}
func renderOAuthCallbackPage(w http.ResponseWriter, flowID, status, title, errMsg string) {
payload := map[string]string{
"type": "picoclaw-oauth-result",
"flowId": flowID,View on GitHub (pinned to 49183d7e8d)
Solutions
- Read the wrapped %v — a JSON syntax error means the store file is corrupt; rename it aside and retry (logout then trivially succeeds with an empty store).
- Fix permissions/ownership on the credentials file and its parent directory for the backend process user.
- Free disk space if the error is a write failure.
- Restart the backend after replacing the store file so any in-process state is consistent.
Example fix
# before
$ curl -X POST localhost:8080/api/oauth/logout -d '{"provider":"openai"}'
{"message":"failed to delete credential: parsing auth store: invalid character ..."}
# after
$ mv ~/.config/picoclaw/auth.json ~/.config/picoclaw/auth.json.bak
$ curl -X POST localhost:8080/api/oauth/logout -H 'Content-Type: application/json' -d '{"provider":"openai"}'
{"status":"ok","provider":"openai"} Defensive patterns
Strategy: try-catch
Validate before calling
await fs.access(credsFile, fs.constants.W_OK); // store must be rewritable for logout to succeed
Try / catch
const res = await fetch('/api/oauth/logout', {...});
if (res.status === 500) {
const { message } = await res.json();
if (/delete credential/i.test(message ?? '')) {
// store file corrupt or unwritable — recover by backing it up and retrying once
await backupAndResetCredentialStore();
return fetch('/api/oauth/logout', {...});
}
throw new Error(message);
} Prevention
- Keep the credentials file valid JSON and writable by the backend user.
- Back up before hand-editing the credential store.
- Remember logout requires rewriting the store — a read-only file blocks logout, not just login.
When it happens
Trigger: POST /api/oauth/logout {"provider":"openai"} when the credential store JSON is invalid (LoadStore unmarshal error), the file or its directory is not writable by the backend user, or the disk is full (SaveStore).
Common situations: Hand-edited or partially written credentials file; running the backend under a different UID than the file owner; credentials file on a read-only mount in a container; ENOSPC.
Related errors
- token login failed: %v
- failed to update config: %v
- failed to load credentials: %v
- no refresh token available
- credential: failed to resolve credential file path %q: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/7b190271f24fde34.
Report an issue: GitHub.