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

  1. 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).
  2. Fix permissions/ownership on the credentials file and its parent directory for the backend process user.
  3. Free disk space if the error is a write failure.
  4. 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

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


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/7b190271f24fde34. Report an issue: GitHub.