we-promise/sure · warning · ActiveRecord::RecordNotDestroyed
Cannot revoke demo monitoring API key
Error message
Cannot revoke demo monitoring API key
What it means
ApiKey#revoke! refuses to revoke the seeded demo monitoring key: if the record's display_key equals the hardcoded DEMO_MONITORING_KEY constant ("demo_monitoring_key_a1b2c3d4…"), it raises ActiveRecord::RecordNotDestroyed instead of setting revoked_at. That key is created by Demo::Generator so the demo family's health can be monitored externally; revoking it would blind the monitor. The same protection exists on delete. It is excluded from the visible scope in the UI, so hitting this usually means direct console/code interaction.
Source
Thrown at app/models/api_key.rb:67
# Instance methods
def active?
!revoked? && !expired?
end
def revoked?
revoked_at.present?
end
def expired?
expires_at.present? && expires_at < Time.current
end
def key_matches?(plain_key)
display_key == plain_key
end
def revoke!
raise ActiveRecord::RecordNotDestroyed, "Cannot revoke demo monitoring API key" if demo_monitoring_key?
update!(revoked_at: Time.current)
end
def delete
raise ActiveRecord::RecordNotDestroyed, "Cannot destroy demo monitoring API key" if demo_monitoring_key?
super
end
def demo_monitoring_key?
display_key == DEMO_MONITORING_KEY
end
def update_last_used!
update_column(:last_used_at, Time.current)
end
# Get the plain text API key for display (automatically decrypted by Rails)
def plain_keyView on GitHub (pinned to e69894adb9)
Solutions
- Scope revocation through the visible scope: ApiKey.visible.each(&:revoke!) — it already excludes the demo key
- If you truly want the demo key gone, disable/remove the demo feature properly (Demo::DataCleaner deletes demo records including this key via delete_all, bypassing the callback guard)
- Exclude it explicitly in custom scripts: next if api_key.demo_monitoring_key?
- If you no longer run a demo family, run the demo cleanup/teardown task rather than revoking the key in place
Example fix
# before ApiKey.all.each(&:revoke!) # => ActiveRecord::RecordNotDestroyed: Cannot revoke demo monitoring API key # after ApiKey.visible.each(&:revoke!) # skips DEMO_MONITORING_KEY by design # or, when tearing the demo down entirely: # Demo::DataCleaner (runs ApiKey.where(display_key: ApiKey::DEMO_MONITORING_KEY).delete_all)
Defensive patterns
Strategy: validation
Validate before calling
# In any revocation script ApiKey.visible.each(&:revoke!) # scope excludes the demo key # or explicitly: keys.reject(&:demo_monitoring_key?).each(&:revoke!)
Type guard
def revocable_api_key?(key) !key.demo_monitoring_key? end
Try / catch
rescue ActiveRecord::RecordNotDestroyed => e
if e.message.include?("demo monitoring API key")
skip # protected demo key: intentionally not revocable
else
raise
end
end Prevention
- Always iterate ApiKey.visible for user-facing key operations
- Check demo_monitoring_key? before revoke/destroy in custom tooling
- Use the demo teardown task to remove demo data wholesale
- Never reuse the reserved DEMO_MONITORING_KEY value in fixtures
When it happens
Trigger: Admin console or script calling api_key.revoke! on the demo monitoring key; a bulk 'revoke all keys' rake task that iterates ApiKey.all (the visible scope excludes it, but all does not); cleanup scripts that revoke keys matching a pattern which happens to include the demo key; attempting revoke after the key was recreated by a demo:refresh job (DemoFamilyRefreshJob manages it and expects it to stay live).
Common situations: Self-hosters hardening their instance by revoking every API key found in the DB, unaware one is load-bearing for demo monitoring; rotating all keys via script; migrating away from the demo and trying to shut its key off through the same code path users' keys go through.
Related errors
- Cannot destroy demo monitoring API key
- record_not_found
- validation_failed
- record_not_found
- record_not_found
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/c878448f3d82ebb8.
Report an issue: GitHub.