#7392·bifrost

[Bug]: DELETE /api/governance/virtual-keys/{id} returns 500 "Failed to delete virtual key" — FOREIGN KEY constraint failed (v2.2.1, SQLite)

Author: sennerCreated Sep 21, 2026Updated Sep 22, 2026
Labelsbug

Version

v2.2.1 (binary extracted from maximhq/bifrost:v2.2.1), default SQLite config store, -app-dir on local disk. Linux/amd64.

What happens

DELETE /api/governance/virtual-keys/{id} returns 500 for certain virtual keys:

DELETE /api/governance/virtual-keys/vk-budget-recheck

Response:

json
{"is_bifrost_error":false,"status_code":500,"error":{"message":"Failed to delete virtual key"},"extra_fields":{"routing_info":{}}}

Server log:

{"level":"error","message":"failed to delete virtual key: FOREIGN KEY constraint failed"}
{"level":"error","http.method":"DELETE","http.target":"/api/governance/virtual-keys/vk-budget-recheck","http.status_code":500,"http.request_duration_ms":1}

PUT on the same key setting is_active: false also returns 500, so an affected key can be neither deleted nor deactivated through the API. Teams and customers delete cleanly; only virtual keys are affected.

What I could NOT reproduce (probably the useful part)

On a clean v2.2.1 instance (fresh config.db each time) I tried five shapes and all deleted successfully with 200:

  1. VK declared in config.json, no team, no budget, empty provider_configs
  2. VK with provider_configs + allow_all_keys: true
  3. VK with a rate_limit_id
  4. VK that had served a successful completion (real provider, usage recorded)
  5. VK in a team, where that team has a budget — and a VK in a team without one

So none of those alone is the trigger.

The difference on the instance that fails

The affected keys live on an instance whose config.json has been edited and reloaded repeatedly — entries added, removed from the file, and re-added across ~6 restarts. (Note config.json appears to be additive against the store: removing an entry from the file does not delete the row.) That accumulated reconciliation state is the only remaining difference I can identify, which may make this adjacent to #7291 / #6863 / #6744.

I could not narrow it further without guessing at the schema, so I am reporting the failure and the negative results rather than a minimal repro.

Expected

Either the delete succeeds, or it fails with a 4xx naming the dependent rows that block it — currently there is no way to discover what the key is still referenced by, and no way to disable it either.

Workaround, for anyone hitting this

If the VK's value is an env. reference, remove that variable from the environment and restart: the credential no longer resolves and the key returns 401 access_not_found. The row stays, but it is inert.

Related

#6648 fixed a very similar "legacy FK constraints block delete" bug for DeleteMCPClientConfig; this looks like the same class on the virtual-key path.