lfnovo/open-notebook · error · HTTPException

Failed to update credential

Error message

Failed to update credential

What it means

Catch-all 500 from PUT /api/credentials/{credential_id}. Raised when the update fails with an unexpected exception beyond the explicit NotFoundError and OpenNotebookError handlers — typically a DB write error or failure while re-fetching/updating linked models.

Source

Thrown at api/routers/credentials.py:302

        try:
            ensure_provider_required_fields(cred)
        except ValueError as e:
            raise _handle_value_error(e)

        await cred.save()
        models = await cred.get_linked_models()
        return credential_to_response(cred, len(models))

    except HTTPException:
        raise
    except NotFoundError:
        raise HTTPException(status_code=404, detail="Credential not found")
    except OpenNotebookError:
        raise
    except Exception as e:
        logger.error(f"Error updating credential {credential_id}: {e}")
        raise HTTPException(status_code=500, detail="Failed to update credential")


@router.delete("/{credential_id}", response_model=CredentialDeleteResponse)
async def delete_credential(
    credential_id: str,
    migrate_to: Optional[str] = Query(
        None, description="Migrate linked models to this credential ID"
    ),
):
    """
    Delete a credential.

    If the credential has linked models:
    - Pass migrate_to=<credential_id> to reassign them to another credential
    - Otherwise, linked models are cascade-deleted automatically
    """
    try:
        try:

View on GitHub (pinned to a7de90d38a)

Solutions

  1. Check logs for 'Error updating credential <id>: ...' — the update may have partially applied; re-fetch to verify state
  2. Confirm DB health and retry the PUT idempotently
  3. If re-encrypting a key, verify OPEN_NOTEBOOK_ENCRYPTION_KEY is stable across requests
  4. If linked-model fetch failed after update, reload the credential to see the persisted state before retrying
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await api.updateCredential(id, patch);
} catch (e) {
  if (e.status === 500) {
    const fresh = await api.getCredential(id).catch(() => null); // did it partially apply?
    if (fresh && matches(fresh, patch)) return fresh; // idempotent recovery
  }
  throw e;
}

Prevention

When it happens

Trigger: Updating a credential (e.g. changing its api_key or clearing base_url) while the DB write fails, or when get_linked_models() errors after a successful update, producing a 500 even though the test test_update_rejects_clearing_compatible_base_url exercises this path.

Common situations: DB connection dropped mid-request, schema mismatch on updated fields, or encryption errors when re-encrypting a rotated API key.

Related errors


AI-assisted analysis of lfnovo/open-notebook@a7de90d38a (2026-08-27). Data as JSON: /api/errors/6c93cb833b9af2fd. Report an issue: GitHub.