denoland/deno · error · Error
${prefix}Linter plugin rules must be an object
Error message
${prefix}Linter plugin rules must be an object What it means
Thrown by installPlugin() in cli/js/40_lint.js when `plugin.rules` is not of type "object". The `rules` map is how the linter discovers a plugin's rules (it later iterates Object.keys(plugin.rules)), so a missing or non-object value makes the plugin unusable. Note the check is a loose typeof: `null` slips past it and fails later, but undefined, strings, numbers, booleans, and functions throw here.
Source
Thrown at cli/js/40_lint.js:504
throw new Error(`${prefix}Linter plugin name must be a string`);
}
if (!/^[a-z-]+$/.test(plugin.name)) {
throw new Error(
`${prefix}Linter plugin name must only contain lowercase letters (a-z) or hyphens (-).`,
);
}
if (plugin.name.startsWith("-") || plugin.name.endsWith("-")) {
throw new Error(
`${prefix}Linter plugin name must start and end with a lowercase letter.`,
);
}
if (plugin.name.includes("--")) {
throw new Error(
`${prefix}Linter plugin name must not have consequtive hyphens.`,
);
}
if (typeof plugin.rules !== "object") {
throw new Error(`${prefix}Linter plugin rules must be an object`);
}
if (state.installedPlugins.has(plugin.name)) {
throw new Error(`Linter plugin ${plugin.name} has already been registered`);
}
state.plugins.push(plugin);
state.installedPlugins.add(plugin.name);
return {
name: plugin.name,
ruleNames: Object.keys(plugin.rules),
};
}
/**
* @param {AstContext} ctx
* @param {number} idx
* @returns {FacadeNode | null}
*/View on GitHub (pinned to 89f33cbef2)
Solutions
- Add a `rules` object mapping rule names to rule objects: rules: { "no-foo": { create(ctx) { ... } } }
- If you exported a single rule, wrap it: export default { name: "pkg", rules: { "rule-name": theRule } }
- Verify the plugin's default export shape against Deno.lint.Plugin types (deno lint --json or the CLI's type declarations)
Example fix
// before
export default {
name: "my-plugin",
rule: {
create(ctx) { /* ... */ },
},
};
// after
export default {
name: "my-plugin",
rules: {
"no-bad-pattern": {
create(ctx) { /* ... */ },
},
},
}; Defensive patterns
Strategy: type-guard
Validate before calling
function assertPluginShape(plugin) {
if (typeof plugin !== "object" || plugin === null) throw new TypeError("plugin must be an object");
if (typeof plugin.name !== "string") throw new TypeError("plugin.name must be a string");
if (typeof plugin.rules !== "object" || plugin.rules === null) {
throw new TypeError("plugin.rules must be a non-null object");
}
for (const [ruleName, rule] of Object.entries(plugin.rules)) {
if (typeof rule?.create !== "function") {
throw new TypeError(`rule '${ruleName}' is missing create(ctx)`);
}
}
} Type guard
/** @param {unknown} p */
function isLintPlugin(p) {
return typeof p === "object" && p !== null &&
typeof /** @type {any} */ (p).name === "string" &&
typeof /** @type {any} */ (p).rules === "object" &&
/** @type {any} */ (p).rules !== null;
} Prevention
- Type your plugin export against Deno's lint plugin types so shape errors surface in `deno check`
- Add a tiny test importing the plugin default export and asserting name/rules/create presence
When it happens
Trigger: A plugin that only declares `name` and forgets `rules`; a plugin whose default export is a rule factory that returns `{ name, rule }` instead of `{ name, rules: { ... } }`; `rules` set to a single rule object's array or a string list.
Common situations: Writing a first Deno lint plugin from memory and omitting the `rules` wrapper; migrating an ESLint rule module where the export shape is `{ meta, create }` and assuming it maps directly; a typo like `rule:` instead of `rules:`.
Related errors
- ${prefix}Linter plugin name must only contain lowercase lett
- ${prefix}Linter plugin name must start and end with a lowerc
- ${prefix}Linter plugin name must not have consequtive hyphen
- Linter plugin ${plugin.name} has already been registered
- Visitor "${name}" of plugin "${id}" errored
AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16).
Data as JSON: /api/errors/eb1a3863988fdafe.
Report an issue: GitHub.