{"record":{"id":"77158c91bf1a1933","repo":"srbhr/Resume-Matcher","slug":"failed-to-delete-applications-please-try-again","errorCode":null,"errorMessage":"Failed to delete applications. Please try again.","messagePattern":"Failed to delete applications\\. Please try again\\.","errorType":"http","errorClass":"HTTPException","httpStatus":500,"severity":"error","filePath":"apps/backend/app/routers/applications.py","lineNumber":172,"sourceCode":"    \"\"\"Delete a card.\"\"\"\n    try:\n        deleted = await db.delete_application(application_id)\n    except Exception as e:\n        logger.error(\"Failed to delete application %s: %s\", application_id, e)\n        raise HTTPException(status_code=500, detail=\"Failed to delete application. Please try again.\")\n    if not deleted:\n        raise HTTPException(status_code=404, detail=\"Application not found\")\n    return ApplicationActionResponse(message=\"Application deleted\", affected=1)\n\n\n@router.post(\"/bulk-delete\", response_model=ApplicationActionResponse)\nasync def bulk_delete_applications(request: BulkDelete) -> ApplicationActionResponse:\n    \"\"\"Delete many cards.\"\"\"\n    try:\n        deleted = await db.bulk_delete_applications(request.application_ids)\n    except Exception as e:\n        logger.error(\"Failed to bulk-delete applications: %s\", e)\n        raise HTTPException(status_code=500, detail=\"Failed to delete applications. Please try again.\")\n    return ApplicationActionResponse(message=f\"Deleted {deleted} application(s)\", affected=deleted)\n\n\nasync def _extract_company_role(job_description: str) -> dict[str, str | None]:\n    \"\"\"Best-effort company/role extraction for the manual-add path.\n\n    Reuses the cached keyword-extraction pass; falls back to blank (editable)\n    on any failure so a flaky LLM never blocks card creation. LLM output isn't\n    guaranteed to be a string, so values are type-guarded before ``.strip()``.\n    \"\"\"\n    try:\n        keywords = await extract_job_keywords(job_description)\n        raw_company = keywords.get(\"company\")\n        raw_role = keywords.get(\"role\")\n        return {\n            \"company\": (raw_company.strip() if isinstance(raw_company, str) else \"\") or None,\n            \"role\": (raw_role.strip() if isinstance(raw_role, str) else \"\") or None,\n        }","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/srbhr/Resume-Matcher/blob/116f9cc3b00e1ac91734a6c2679bf41ea64a0edc/apps/backend/app/routers/applications.py#L154-L190","documentation":"This 500 HTTPException is raised by bulk_delete_applications when db.bulk_delete_applications(request.application_ids) throws. It wraps any persistence-layer exception during multi-delete and hides details from the client while logging server-side. Note the non-transactional semantics: some documents may have been deleted before the failure.","triggerScenarios":"POST /applications/bulk-delete with an application_ids list that causes the db layer to raise: DB connection failure, invalid id format in the list causing driver cast errors, or oversized delete query.","commonSituations":"Batch contains one malformed/legacy id that breaks the whole delete, MongoDB timeout on very large batches, or DB outage mid-request.","solutions":["Check backend logs for 'Failed to bulk-delete applications' for the root cause","Validate/normalize every id in application_ids before sending (correct type/format)","Retry with a smaller batch to isolate a problematic id","Verify database connectivity and health"],"exampleFix":"// before\nawait api.bulkDeleteApplications(ids)\n// after\nconst valid = ids.filter((id) => /^[a-f\\d]{24}$/i.test(id))\nif (valid.length !== ids.length) console.warn('dropping invalid ids')\nawait api.bulkDeleteApplications(valid)","handlingStrategy":"validation","validationCode":"const valid = ids.filter(id => typeof id === 'string' && id.length > 0)\nif (valid.length === 0) throw new Error('no valid ids to delete')","typeGuard":null,"tryCatchPattern":"try {\n  await api.bulkDeleteApplications(ids)\n} catch (e) {\n  if (e.response?.status === 500) {\n    // fall back to per-id deletes to salvage partial progress\n    await Promise.allSettled(ids.map(id => api.deleteApplication(id)))\n  }\n}","preventionTips":["Validate id format/types before sending the batch","Chunk very large batches into smaller deletes","Check backend logs for the logged root-cause exception","Assume partial deletion may have occurred and reconcile by re-listing"],"tags":["http-500","database","bulk-delete"],"backgroundTag":"database-operation-failed","analyzedSha":"116f9cc3b00e1ac91734a6c2679bf41ea64a0edc","analyzedAt":"2026-08-28T22:51:40.999Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}