eslint/eslint · error · Error
`SourceCode#${methodName}()` cannot be called inside a rule.
Error message
`SourceCode#${methodName}()` cannot be called inside a rule. What it means
Thrown by throwForbiddenMethodError() at lib/rule-tester/rule-tester.js:323 for the methods in forbiddenMethods: applyInlineConfig, applyLanguageOptions, finalize. RuleTester monkeypatches SourceCode.prototype so each of these methods can be called at most once per SourceCode instance — the first call (the legitimate one by the linter's config-apply pipeline) is allowed through, any subsequent call (i.e. a rule calling it) throws.
Source
Thrown at lib/rule-tester/rule-tester.js:323
* @param {string} methodName The name of the method to forbid.
* @param {Function} prototype The prototype with the original method to call.
* @returns {Function} The function that throws the error.
*/
function throwForbiddenMethodError(methodName, prototype) {
const original = prototype[methodName];
return function (...args) {
const called = forbiddenMethodCalls.get(methodName);
/* eslint-disable no-invalid-this -- needed to operate as a method. */
if (!called.has(this)) {
called.add(this);
return original.apply(this, args);
}
/* eslint-enable no-invalid-this -- not needed past this point */
throw new Error(
`\`SourceCode#${methodName}()\` cannot be called inside a rule.`,
);
};
}
/**
* Extracts names of {{ placeholders }} from the reported message.
* @param {string} message Reported message
* @returns {string[]} Array of placeholder names
*/
function getMessagePlaceholders(message) {
const matcher = getPlaceholderMatcher();
return Array.from(message.matchAll(matcher), ([, name]) => name.trim());
}
/**
* Returns the placeholders in the reported messages butView on GitHub (pinned to f131c034ad)
Solutions
- Remove the call to applyInlineConfig / applyLanguageOptions / finalize from the rule body — these are the linter's responsibility.
- If the rule needs language options, read them from `context.languageOptions` instead of forcing application.
- If the rule needs inline config effects, that indicates a design issue; restructure so the rule reads already-applied state.
Example fix
// before
create(context) {
context.sourceCode.applyInlineConfig();
return { Program(node) { /* ... */ } };
}
// after
create(context) {
return { Program(node) { /* ... */ } };
} Defensive patterns
Strategy: validation
Validate before calling
const FORBIDDEN = new Set(["applyInlineConfig","applyLanguageOptions","finalize"]);
const ruleSrc = require('node:fs').readFileSync(rulePath,'utf8');
for (const m of FORBIDDEN) {
if (ruleSrc.includes(`sourceCode.${m}`) || ruleSrc.includes(`.sourceCode.${m}`)) {
throw new Error(`Rule must not call SourceCode#${m}()`);
}
} Type guard
/** @param {string} method */
function isForbiddenSourceCodeMethod(method) {
return ["applyInlineConfig","applyLanguageOptions","finalize"].includes(method);
} Prevention
- Treat applyInlineConfig/applyLanguageOptions/finalize as linter-internal; never call them from rules.
- Read language settings from `context.languageOptions` instead of forcing application.
- If you think you need these methods, you are likely re-implementing the linter's pipeline.
When it happens
Trigger: Inside a rule's `create()` handler, the rule explicitly calls `context.sourceCode.applyInlineConfig()`, `.applyLanguageOptions()`, or `.finalize()`, causing a second invocation of that method on the same SourceCode instance during a test. These methods are part of the linter's lifecycle and are not meant to be invoked by rule code.
Common situations: A rule author mistakenly thinks they need to apply inline config or finalize the source code themselves; copy-paste from the core Linter pipeline into a rule; a rule that mutates SourceCode state expecting re-initialization.
Related errors
- Use ${objName}.range[0] instead of ${objName}.start
- Use ${objName}.range[1] instead of ${objName}.end
- `schema: {}` is a no-op${metaSchemaDescription}
- Schema for rule ${ruleName} is invalid:
- Schema for rule ${ruleName} is invalid: ${err.message}
AI-assisted analysis of eslint/eslint@f131c034ad (2026-08-03).
Data as JSON: /data/errors/3d058c16cd4030de.json.
Report an issue: GitHub.