{"record":{"id":"f6fbdf9f3f621bc9","repo":"facebook/docusaurus","slug":"extension-ext-contains-a-dot-which-is-n","errorCode":null,"errorMessage":"Extension \"${ext}\" contains a \".\" (dot) which is not allowed.\nIf the redirect extension system is not good enough for your use case, you can create redirects yourself with the \"createRedirects\" plugin option.","messagePattern":"Extension \"(.+?)\" contains a \"\\.\" \\(dot\\) which is not allowed\\.\nIf the redirect extension system is not good enough for your use case, you can create redirects yourself with the \"createRedirects\" plugin option\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/docusaurus-plugin-client-redirects/src/extensionRedirects.ts","lineNumber":25,"sourceCode":"\nimport {\n  addTrailingSlash,\n  removeSuffix,\n  removeTrailingSlash,\n} from '@docusaurus/utils-common';\nimport type {RedirectItem} from './types';\n\nconst ExtensionAdditionalMessage =\n  'If the redirect extension system is not good enough for your use case, you can create redirects yourself with the \"createRedirects\" plugin option.';\n\nconst validateExtension = (ext: string) => {\n  if (!ext) {\n    throw new Error(\n      `Extension \"${ext}\" is not allowed.\\n${ExtensionAdditionalMessage}`,\n    );\n  }\n  if (ext.includes('.')) {\n    throw new Error(\n      `Extension \"${ext}\" contains a \".\" (dot) which is not allowed.\\n${ExtensionAdditionalMessage}`,\n    );\n  }\n  if (ext.includes('/')) {\n    throw new Error(\n      `Extension \"${ext}\" contains a \"/\" (slash) which is not allowed.\\n${ExtensionAdditionalMessage}`,\n    );\n  }\n  if (encodeURIComponent(ext) !== ext) {\n    throw new Error(\n      `Extension \"${ext}\" contains invalid URI characters.\\n${ExtensionAdditionalMessage}`,\n    );\n  }\n};\n\nconst addLeadingDot = (extension: string) => `.${extension}`;\n\n/**","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/facebook/docusaurus/blob/3f483e80e326cc646b54b83d564b3f0c4881b9a6/packages/docusaurus-plugin-client-redirects/src/extensionRedirects.ts#L7-L43","documentation":"Thrown by validateExtension() when an extension string in fromExtensions/toExtensions contains a '.' character. Extensions are plain tokens (e.g. 'html'); the plugin adds the leading dot itself via addLeadingDot, so a user-supplied dot would create a double dot ('..html') and is rejected.","triggerScenarios":"Configuring fromExtensions: ['.html'] or toExtensions: ['html.json']; passing extensions that include a filename-style value. Reached in the same forEach(validateExtension) loop as the other extension checks.","commonSituations":"Intuitively writing '.html' because that is how extensions look in filenames; copying a config snippet from a blog that uses dotted extensions; feeding file extensions extracted with path.extname (which includes the dot).","solutions":["Drop the leading dot: use 'html' instead of '.html'.","If generating extensions from path.extname(file), slice off the first character: ext.slice(1).","Keep extensions as single tokens with no dot, slash, or URI-unsafe characters."],"exampleFix":"// before\nfromExtensions: ['.html'],\n// after\nfromExtensions: ['html'],","handlingStrategy":"validation","validationCode":"function stripLeadingDot(ext: string): string {\n  if (ext.startsWith('.')) {\n    throw new Error(`Extension \"${ext}\" contains a \".\" which is not allowed. Use \"${ext.slice(1)}\".`);\n  }\n  return ext;\n}","typeGuard":"const isBareExtension = (e: unknown): e is string =>\n  typeof e === 'string' && !!e && !e.includes('.') && !e.includes('/')\n  && encodeURIComponent(e) === e;","tryCatchPattern":null,"preventionTips":["Write extensions without a leading dot ('html', not '.html').","If deriving from path.extname, drop the dot: ext.slice(1).","Add a config lint that rejects dotted extensions."],"tags":["plugin-client-redirects","redirects","extensions","validation"],"backgroundTag":null,"analyzedSha":"3f483e80e326cc646b54b83d564b3f0c4881b9a6","analyzedAt":"2026-08-12T13:25:04.382Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}