{"record":{"id":"b1a56e22209271a7","repo":"denoland/deno","slug":"prefix-linter-plugin-name-must-start-and-end-wit","errorCode":null,"errorMessage":"${prefix}Linter plugin name must start and end with a lowercase letter.","messagePattern":"(.+?)Linter plugin name must start and end with a lowercase letter\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"cli/js/40_lint.js","lineNumber":494,"sourceCode":"  // When the plugin was loaded from a specifier (i.e. `lint.plugins` in the\n  // config), prefix validation errors with it so the user knows which plugin\n  // is misbehaving instead of getting an anonymous error.\n  const prefix = typeof specifier === \"string\"\n    ? `Failed to load lint plugin '${specifier}': `\n    : \"\";\n  if (typeof plugin !== \"object\") {\n    throw new Error(`${prefix}Linter plugin must be an object`);\n  }\n  if (typeof plugin.name !== \"string\") {\n    throw new Error(`${prefix}Linter plugin name must be a string`);\n  }\n  if (!/^[a-z-]+$/.test(plugin.name)) {\n    throw new Error(\n      `${prefix}Linter plugin name must only contain lowercase letters (a-z) or hyphens (-).`,\n    );\n  }\n  if (plugin.name.startsWith(\"-\") || plugin.name.endsWith(\"-\")) {\n    throw new Error(\n      `${prefix}Linter plugin name must start and end with a lowercase letter.`,\n    );\n  }\n  if (plugin.name.includes(\"--\")) {\n    throw new Error(\n      `${prefix}Linter plugin name must not have consequtive hyphens.`,\n    );\n  }\n  if (typeof plugin.rules !== \"object\") {\n    throw new Error(`${prefix}Linter plugin rules must be an object`);\n  }\n  if (state.installedPlugins.has(plugin.name)) {\n    throw new Error(`Linter plugin ${plugin.name} has already been registered`);\n  }\n  state.plugins.push(plugin);\n  state.installedPlugins.add(plugin.name);\n\n  return {","sourceCodeStart":476,"sourceCodeEnd":512,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/cli/js/40_lint.js#L476-L512","documentation":"After the charset check, Deno's lint plugin loader also rejects plugin names whose first or last character is a hyphen (plugin.name.startsWith(\"-\") || plugin.name.endsWith(\"-\") in cli/js/40_lint.js). The rule exists so names are always parseable as kebab-case tokens inside rule ids like \"plugin-name/rule-name\". The message is prefixed with \"Failed to load lint plugin '<specifier>': \" when the plugin came from a specifier.","triggerScenarios":"Installing a lint plugin whose `name` is \"-my-plugin\", \"my-plugin-\", or just \"-\". The name already passed /^[a-z-]+$/ (so it is only lowercase letters and hyphens) but has a leading or trailing hyphen.","commonSituations":"Hand-truncating a longer name and leaving a hyphen (\"my-plugin\" cut to \"-plugin\"); generating names by splitting a phrase on spaces and joining with '-' including empty parts; typos.","solutions":["Remove the leading or trailing hyphen so the name starts and ends with a lowercase letter (\"my-plugin\").","If the name is generated, trim '-' from both ends: name.replace(/^-+|-+$/g, \"\").","Re-run `deno lint` to confirm the plugin installs."],"exampleFix":"// before\nexport default {\n  name: \"-strict-rules-\",\n  rules: {},\n};\n\n// after\nexport default {\n  name: \"strict-rules\",\n  rules: {},\n};","handlingStrategy":"validation","validationCode":"function normalizePluginName(name) {\n  return String(name).replace(/[^a-z-]+/g, \"-\").replace(/^-+|-+$/g, \"\");\n}\nconst plugin = { name: normalizePluginName(rawName), rules };","typeGuard":"/** @param {unknown} name @returns {boolean} */\nfunction hasCleanNameEdges(name) {\n  return typeof name === \"string\" && /^[a-z](.*[a-z])?$/.test(name);\n}","tryCatchPattern":"try {\n  installPlugin(plugin);\n} catch (err) {\n  if (err.message.includes(\"must start and end with a lowercase letter\")) {\n    plugin.name = plugin.name.replace(/^-+|-+$/g, \"\"); // then retry once\n  } else throw err;\n}","preventionTips":["When assembling names from parts, filter empty segments before joining with '-'.","Include the edge check (no leading/trailing '-') in the plugin's own unit test."],"tags":["deno","deno-lint","lint-plugin","validation","naming"],"backgroundTag":"plugin-validation-failed","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}