{"record":{"id":"33047de33112e423","repo":"instructure/canvas-lms","slug":"please-don-t-turn-off-the-default-developer-key","errorCode":null,"errorMessage":"Please don't turn off the default developer key","messagePattern":"Please don't turn off the default developer key","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/models/developer_key_account_binding.rb","lineNumber":162,"sourceCode":"  end\n\n  alias_method :allowed?, :allow?\n\n  private\n\n  def for_default_key?\n    developer_key&.name == DeveloperKey::DEFAULT_KEY_NAME &&\n      developer_key == DeveloperKey.default(create_if_missing: false)\n  end\n\n  # DeveloperKey.default is for user-generated tokens and must always be ON\n  def enable_default_key\n    self.workflow_state = :on if !on? && for_default_key?\n  end\n\n  # DeveloperKey.default is for user-generated tokens and must always be ON\n  def protect_default_key_binding\n    raise \"Please don't turn off the default developer key\" if !on? && for_default_key?\n  end\n\n  def set_root_account\n    self.root_account_id ||= account&.resolved_root_account_id\n  end\n\n  def update_tools!\n    if disable_tools? || delete_tools?\n      developer_key.disable_external_tools!(account)\n    elsif enable_tools?\n      developer_key.enable_external_tools!(account)\n    elsif restore_tools?\n      developer_key.restore_external_tools!(account)\n    end\n  end\n\n  def enable_tools?\n    saved_change_to_workflow_state? && on?","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/models/developer_key_account_binding.rb#L144-L180","documentation":"DeveloperKeyAccountBinding#protect_default_key_binding enforces that the account binding for the site default developer key is always workflow_state :on, because the default key must remain usable for user-generated tokens. Turning the binding off (or deleting it) triggers this raise.","triggerScenarios":"Setting workflow_state to :off/:allow on a binding where for_default_key? is true (binding whose developer_key is DeveloperKey.default); deleting the default key's binding; account-level API updates that disable the default key.","commonSituations":"Admin toggling 'off' on the default key in an account settings page; scripts bulk-disabling developer key bindings per account; API PATCH to developer_key_account_bindings targeting the default key.","solutions":["Never set the default key's binding to :off/:allow; leave it :on","Exclude the default key's binding from bulk disable scripts (skip where binding.for_default_key?)","Use the enable_default_key path (it auto-forces :on) rather than manually setting workflow_state","If the intent is to restrict LTI tools, disable the specific tool keys, not the default key binding"],"exampleFix":"// before\nbinding.workflow_state = :off\nbinding.save!\n// after\nraise \"cannot disable default key binding\" if binding.for_default_key?\nbinding.workflow_state = :off\nbinding.save!","handlingStrategy":"validation","validationCode":"next if binding.for_default_key? # skip default key bindings\nbinding.update(workflow_state: :off)","typeGuard":null,"tryCatchPattern":"begin\n  binding.update!(workflow_state: :off)\nrescue RuntimeError => e\n  raise unless e.message =~ /default developer key/\n  Rails.logger.warn('cannot disable default key binding')\nend","preventionTips":["Never toggle workflow_state on bindings where for_default_key? is true","Use admin UI/API paths that enforce the on state for the default key","Scope bulk binding updates to non-default keys"],"tags":["ruby","rails","developer-key","account-binding","lti"],"backgroundTag":"invalid-state-transition","analyzedSha":"1c9f0bb8013ed69c4f2efe11fd483025469b7e6c","analyzedAt":"2026-09-15T20:33:18.891Z","contentChangedAt":"2026-09-15T20:33:18.891Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}