Summary
Hard-deleting an agent (or company) that has heartbeat_runs entries fails with HTTP 500 because cost_events.heartbeat_run_id has a foreign key into heartbeat_runs that the delete path doesn't clean up first.
Reproduction
- Fresh onboard via
pnpm paperclipai run (local_trusted mode)
- Create a company and an agent
- Run at least one heartbeat (
pnpm paperclipai heartbeat run --agent-id <id>) so cost_events rows exist
curl -X DELETE http://localhost:3100/api/agents/<id>
Expected
HTTP 200, agent deleted.
Actual
HTTP 500. Server log:
update or delete on table "heartbeat_runs" violates foreign key constraint "cost_events_heartbeat_run_id_heartbeat_runs_id_fk" on table "cost_events"
Postgres detail: Key (id)=(<heartbeat-run-id>) is still referenced from table "cost_events".
Workaround
PATCH agent status to terminated and POST to /api/companies/:id/archive. Company remains in the default GET /api/companies list though — see separate issue about archived-company filtering.
Versions
- Paperclip:
canary/v2026.416.1-canary.4 (CLI reports 0.3.1)
- Postgres: embedded (54329)
- Windows 11
Summary
Hard-deleting an agent (or company) that has
heartbeat_runsentries fails with HTTP 500 becausecost_events.heartbeat_run_idhas a foreign key intoheartbeat_runsthat the delete path doesn't clean up first.Reproduction
pnpm paperclipai run(local_trusted mode)pnpm paperclipai heartbeat run --agent-id <id>) so cost_events rows existcurl -X DELETE http://localhost:3100/api/agents/<id>Expected
HTTP 200, agent deleted.
Actual
HTTP 500. Server log:
update or delete on table "heartbeat_runs" violates foreign key constraint "cost_events_heartbeat_run_id_heartbeat_runs_id_fk" on table "cost_events"Postgres detail:
Key (id)=(<heartbeat-run-id>) is still referenced from table "cost_events".Workaround
PATCH agent status to
terminatedand POST to/api/companies/:id/archive. Company remains in the defaultGET /api/companieslist though — see separate issue about archived-company filtering.Versions
canary/v2026.416.1-canary.4(CLI reports 0.3.1)