denoland/deno · error · Error
${prefix}Linter plugin name must start and end with a lowerc
Error message
${prefix}Linter plugin name must start and end with a lowercase letter. What it means
Thrown by installPlugin() in cli/js/40_lint.js when the plugin name passes the /^[a-z-]+$/ character check but begins or ends with a hyphen. Leading/trailing hyphens would produce rule ids like "-plugin/rule" and "plugin-/rule", so they are rejected to keep ids clean.
Source
Thrown at cli/js/40_lint.js:494
// When the plugin was loaded from a specifier (i.e. `lint.plugins` in the
// config), prefix validation errors with it so the user knows which plugin
// is misbehaving instead of getting an anonymous error.
const prefix = typeof specifier === "string"
? `Failed to load lint plugin '${specifier}': `
: "";
if (typeof plugin !== "object") {
throw new Error(`${prefix}Linter plugin must be an object`);
}
if (typeof plugin.name !== "string") {
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 {View on GitHub (pinned to 89f33cbef2)
Solutions
- Remove the leading/trailing hyphen so the name starts and ends with a lowercase letter
- If you wanted a namespace prefix, fold it into the name with an inner hyphen, e.g. "internal-plugin"
Example fix
// before
export default { name: "-internal-plugin", rules: {} };
// after
export default { name: "internal-plugin", rules: {} }; Defensive patterns
Strategy: validation
Validate before calling
function assertNoEdgeHyphens(name) {
if (name.startsWith("-") || name.endsWith("-")) {
throw new TypeError(`'${name}' must start and end with a lowercase letter`);
}
} Type guard
function hasNoEdgeHyphens(name) {
return !name.startsWith("-") && !name.endsWith("-");
} Prevention
- Use one canonical construction like kebab-case of the npm/jsr package name
- Lint your own plugin source with a naming rule or a simple test
When it happens
Trigger: A plugin `name` like "-my-plugin" or "my-plugin-". Only fires after the character-set check passes, so the name is otherwise lowercase/hyphen only but has an edge hyphen.
Common situations: Renaming a plugin with a scope-like prefix ("-internal-plugin") to mark it private; a typo adding a trailing hyphen while editing the name string.
Related errors
- ${prefix}Linter plugin name must only contain lowercase lett
- ${prefix}Linter plugin name must not have consequtive hyphen
- ${prefix}Linter plugin rules must be an object
- 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/b1a56e22209271a7.
Report an issue: GitHub.