Skip to content

Prevent calling messenger actions in controller/service constructors#8353

Open
mcmire wants to merge 7 commits intomainfrom
prevent-calling-messenger-actions-in-constructor
Open

Prevent calling messenger actions in controller/service constructors#8353
mcmire wants to merge 7 commits intomainfrom
prevent-calling-messenger-actions-in-constructor

Conversation

@mcmire
Copy link
Copy Markdown
Contributor

@mcmire mcmire commented Mar 31, 2026

Explanation

Some controllers or services call actions from other controllers or services in the constructor (e.g. to populate local or persisted state). But this practice is not recommended, as it forces clients to use a specific order when instantiating controllers and services.

This commit updates the controller guidelines to advise against this practice and adds a lint rule to prevent it from appearing again.

References

No ticket, but I discovered while going through PerpsController that RemoteFeatureFlagController:getState is being called in the constructor.

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

Note

Medium Risk
Medium risk because it changes repo-wide ESLint behavior and introduces a new no-restricted-syntax selector that may surface new lint failures or require additional suppressions across many packages.

Overview
Updates controller guidelines to explicitly ban calling messenger actions in constructors and recommends deferring such work to an init() method.

Enforces the guideline via a new repo-wide no-restricted-syntax rule in eslint.config.mjs (including in packages/*/src/index.ts alongside the existing export restrictions), and expands eslint-suppressions.json with the initial set of suppressions for affected packages/files.

Written by Cursor Bugbot for commit 640126c. This will update automatically on new commits. Configure here.

Some controllers or services call actions from other controllers or
services in the constructor (e.g. to populate local or persisted state).
But this practice is not recommended, as it forces clients to use a
specific order when instantiating controllers and services.

This commit updates the controller guidelines to advise against this
practice and adds a lint rule to prevent it from appearing again.
"count": 6
}
},
"packages/assets-controller/src/AssetsController.ts": {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that the no-restricted-syntax rule in @metamask/eslint-config-typescript overrides the rule in @metamask/eslint-config. We are effectively adding back the rule from @metamask/eslint-config in this commit. So a lot of these changes don't have anything to do with the new lint rule but are merely a side effect of using this collectExistingRuleOptions function I added in a previous PR.

Most of the violations of no-restricted-syntax are The "in" operator is not allowed. Here are all of the violations of the new lint rule:

core/packages/assets-controller/src/AssetsController.ts
   743:44  error  Do not call messenger actions in the constructor, as this forces clients to instantiate controllers or services in a specific order. Move this call to an init() method instead. Read the controller guidelines for more: ..  no-restricted-syntax

core/packages/assets-controller/src/data-sources/RpcDataSource.ts
  262:23  error  Do not call messenger actions in the constructor, as this forces clients to instantiate controllers or services in a specific order. Move this call to an init() method instead. Read the controller guidelines for more: ..  no-restricted-syntax
  274:16  error  Do not call messenger actions in the constructor, as this forces clients to instantiate controllers or services in a specific order. Move this call to an init() method instead. Read the controller guidelines for more: ..  no-restricted-syntax

core/packages/assets-controllers/src/AccountTrackerController.ts
  344:28  error  Do not call messenger actions in the constructor, as this forces clients to instantiate controllers or services in a specific order. Move this call to an init() method instead. Read the controller guidelines for more: ..  no-restricted-syntax

core/packages/assets-controllers/src/MultichainAssetsRatesController/MultichainAssetsRatesController.ts
  244:51  error  Do not call messenger actions in the constructor, as this forces clients to instantiate controllers or services in a specific order. Move this call to an init() method instead. Read the controller guidelines for more: ..  no-restricted-syntax

core/packages/assets-controllers/src/NftController.ts
   415:31  error  Do not call messenger actions in the constructor, as this forces clients to instantiate controllers or services in a specific order. Move this call to an init() method instead. Read the controller guidelines for more: ..  no-restricted-syntax

core/packages/assets-controllers/src/TokenBalancesController.ts
  405:7   error  Do not call messenger actions in the constructor, as this forces clients to instantiate controllers or services in a specific order. Move this call to an init() method instead. Read the controller guidelines for more: ..  no-restricted-syntax
  410:28  error  Do not call messenger actions in the constructor, as this forces clients to instantiate controllers or services in a specific order. Move this call to an init() method instead. Read the controller guidelines for more: ..  no-restricted-syntax

core/packages/assets-controllers/src/TokenDetectionController.ts
  282:35  error  Do not call messenger actions in the constructor, as this forces clients to instantiate controllers or services in a specific order. Move this call to an init() method instead. Read the controller guidelines for more: ..  no-restricted-syntax
  288:61  error  Do not call messenger actions in the constructor, as this forces clients to instantiate controllers or services in a specific order. Move this call to an init() method instead. Read the controller guidelines for more: ..  no-restricted-syntax
  297:28  error  Do not call messenger actions in the constructor, as this forces clients to instantiate controllers or services in a specific order. Move this call to an init() method instead. Read the controller guidelines for more: ..  no-restricted-syntax

core/packages/core-backend/src/AccountActivityService.ts
  246:5  error  Do not call messenger actions in the constructor, as this forces clients to instantiate controllers or services in a specific order. Move this call to an init() method instead. Read the controller guidelines for more: ..  no-restricted-syntax

core/packages/gas-fee-controller/src/GasFeeController.ts
  417:43  error  Do not call messenger actions in the constructor, as this forces clients to instantiate controllers or services in a specific order. Move this call to an init() method instead. Read the controller guidelines for more: ..  no-restricted-syntax
  420:29  error  Do not call messenger actions in the constructor, as this forces clients to instantiate controllers or services in a specific order. Move this call to an init() method instead. Read the controller guidelines for more: ..  no-restricted-syntax

core/packages/perps-controller/src/PerpsController.ts
  909:45  error  Do not call messenger actions in the constructor, as this forces clients to instantiate controllers or services in a specific order. Move this call to an init() method instead. Read the controller guidelines for more: ..  no-restricted-syntax

core/packages/profile-sync-controller/src/controllers/user-storage/UserStorageController.ts
  307:13  error  Do not call messenger actions in the constructor, as this forces clients to instantiate controllers or services in a specific order. Move this call to an init() method instead. Read the controller guidelines for more: ..  no-restricted-syntax
  312:26  error  Do not call messenger actions in the constructor, as this forces clients to instantiate controllers or services in a specific order. Move this call to an init() method instead. Read the controller guidelines for more: ..  no-restricted-syntax

core/packages/selected-network-controller/src/SelectedNetworkController.ts
  156:5   error  Do not call messenger actions in the constructor, as this forces clients to instantiate controllers or services in a specific order. Move this call to an init() method instead. Read the controller guidelines for more: ..  no-restricted-syntax
  162:11  error  Do not call messenger actions in the constructor, as this forces clients to instantiate controllers or services in a specific order. Move this call to an init() method instead. Read the controller guidelines for more: ..  no-restricted-syntax
  178:17  error  Do not call messenger actions in the constructor, as this forces clients to instantiate controllers or services in a specific order. Move this call to an init() method instead. Read the controller guidelines for more: ..  no-restricted-syntax

core/packages/transaction-controller/src/TransactionController.ts
   982:14  error  Do not call messenger actions in the constructor, as this forces clients to instantiate controllers or services in a specific order. Move this call to an init() method instead. Read the controller guidelines for more: ..  no-restricted-syntax
   991:16  error  Do not call messenger actions in the constructor, as this forces clients to instantiate controllers or services in a specific order. Move this call to an init() method instead. Read the controller guidelines for more: ..  no-restricted-syntax

@mcmire mcmire marked this pull request as ready for review March 31, 2026 16:52
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

const NO_MESSENGER_ACTIONS_IN_CONSTRUCTORS_RULES = [
{
selector:
'MethodDefinition[kind="constructor"] CallExpression[callee.type="MemberExpression"][callee.property.name="call"][callee.object.type="MemberExpression"][callee.object.object.type="ThisExpression"][callee.object.property.name="messenger"]',
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Constructor rule misses direct messenger calls

Medium Severity

The no-restricted-syntax selector only matches this.messenger.call(...) in constructors. A constructor can still call messenger.call(...) via its parameter or a local alias, so the new rule does not fully enforce the “no messenger actions in constructors” policy.

Fix in Cursor Fix in Web

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mcmire This seems accurate to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants