{"record":{"id":"4e5e5396de65f66e","repo":"lfnovo/open-notebook","slug":"failed-to-delete-credential","errorCode":null,"errorMessage":"Failed to delete credential","messagePattern":"Failed to delete credential","errorType":"http","errorClass":"HTTPException","httpStatus":500,"severity":"error","filePath":"api/routers/credentials.py","lineNumber":403,"sourceCode":"                deleted_models += 1\n\n        # Delete the credential\n        await cred.delete()\n\n        return CredentialDeleteResponse(\n            message=\"Credential deleted successfully\",\n            deleted_models=deleted_models,\n        )\n\n    except HTTPException:\n        raise\n    except NotFoundError:\n        raise HTTPException(status_code=404, detail=\"Credential not found\")\n    except OpenNotebookError:\n        raise\n    except Exception as e:\n        logger.error(f\"Error deleting credential {credential_id}: {e}\")\n        raise HTTPException(status_code=500, detail=\"Failed to delete credential\")\n\n\n# =============================================================================\n# Test / Discover / Register endpoints\n# =============================================================================\n\n\n@router.post(\"/{credential_id}/test\")\nasync def test_credential(credential_id: str):\n    \"\"\"Test connection using this credential's configuration.\"\"\"\n    return await svc_test_credential(credential_id)\n\n\n@router.post(\"/{credential_id}/discover\", response_model=DiscoverModelsResponse)\nasync def discover_models_for_credential(credential_id: str):\n    \"\"\"Discover available models using this credential's API key.\"\"\"\n    try:\n        cred = await Credential.get(credential_id)","sourceCodeStart":385,"sourceCodeEnd":421,"githubUrl":"https://github.com/lfnovo/open-notebook/blob/a7de90d38aaf18ee85fd661854d35c11e44613e2/api/routers/credentials.py#L385-L421","documentation":"Catch-all 500 from DELETE /api/credentials/{credential_id}. The delete endpoint supports a migrate_to query param that moves or deletes linked models first; any unexpected exception in that migration/deletion logic or the DB writes surfaces here.","triggerScenarios":"DELETE with ?migrate_to=<other_credential_id> where migrating linked models fails (target credential invalid, model update error), or plain DELETE when the DB write fails partway (some linked models already deleted).","commonSituations":"Migrating models to a credential that was concurrently deleted, DB timeout during multi-record model updates, or partial failure leaving orphaned models.","solutions":["Check logs for 'Error deleting credential <id>: ...' and inspect how far the migration got","List models to see which were migrated/deleted before the failure; clean up orphans manually if needed","Verify migrate_to points to an existing credential before retrying","Retry the delete once DB health is confirmed; a retry after partial migration is safe if migrate_to still resolves"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// verify migrate_to target exists before delete-with-migration\nif (migrateTo) {\n  const creds = await api.listCredentials();\n  if (!creds.some(c => c.id === migrateTo)) throw new Error('Migration target credential not found');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await api.deleteCredential(id, { migrate_to: migrateTo });\n} catch (e) {\n  if (e.status === 500) {\n    // partial migration possible: audit linked models before retrying\n    await auditModelsForCredential(id);\n  }\n  throw e;\n}","preventionTips":["Validate the migrate_to credential exists first","Audit linked models after a failed delete-with-migration to catch partial state"],"tags":["credentials","delete","migration","http-500"],"backgroundTag":"http-500-fallback","analyzedSha":"a7de90d38aaf18ee85fd661854d35c11e44613e2","analyzedAt":"2026-08-27T02:39:58.166Z","schemaVersion":2},"datasetVersion":"2026-08-27T03:17:27.898Z"}