{"record":{"id":"9b4ca550d006b9d1","repo":"withastro/astro","slug":"could-not-generate-a-valid-regex-from-the-remotepa","errorCode":null,"errorMessage":"Could not generate a valid regex from the remotePattern \"${JSON.stringify(pattern)}\". Please check the syntax.","messagePattern":"Could not generate a valid regex from the remotePattern \"(.+?)\"\\. Please check the syntax\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/integrations/netlify/src/index.ts","lineNumber":111,"sourceCode":"\t\t\t// Exact match\n\t\t\tregexStr += `(${escapeRegex(pathname)})`;\n\t\t}\n\t} else {\n\t\t// Default to matching any path\n\t\tregexStr += '(\\\\/[^?#]*)?';\n\t}\n\tif (!regexStr.endsWith('.*)')) {\n\t\t// Match query, but only if it's not already matched by the pathname\n\t\tregexStr += '([?][^#]*)?';\n\t}\n\t// Anchor to end of string so .test() can't match a prefix\n\tregexStr += '$';\n\ttry {\n\t\t// nosemgrep: javascript.lang.security.audit.detect-non-literal-regexp.detect-non-literal-regexp\n\t\t// This only validates the generated pattern before handing it to Netlify.\n\t\tnew RegExp(regexStr);\n\t} catch {\n\t\tlogger.warn(\n\t\t\t`Could not generate a valid regex from the remotePattern \"${JSON.stringify(\n\t\t\t\tpattern,\n\t\t\t)}\". Please check the syntax.`,\n\t\t);\n\t\treturn undefined;\n\t}\n\treturn regexStr;\n}\n\nfunction remoteImagesFromAstroConfig(\n\tconfig: AstroConfig,\n\tlogger: AstroIntegrationLogger,\n): string[] {\n\tconst remoteImages: string[] = [];\n\t// Domains get a simple regex match\n\tremoteImages.push(\n\t\t...config.image.domains.map((domain) => `^https?:\\/\\/${escapeRegex(domain)}\\/.*$`),\n\t);","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/withastro/astro/blob/3578d45d34226d63cff3d261c971c221de6794d2/packages/integrations/netlify/src/index.ts#L93-L129","documentation":"The Netlify adapter converts each config.image.remotePatterns entry into a JavaScript regex so it can be written into Netlify's image CDN configuration (remotePatternToRegex). Before handing the regex off, it sanity-compiles it with new RegExp(); if construction throws, the pattern is unusable, this warning prints, and the pattern is skipped (returns undefined), so those remote images will not be optimized.","triggerScenarios":" An entry in image.remotePatterns whose fields produce an invalid regex: e.g. a port that is not numeric ('port: \"80:90\"' interpolated raw into ':80:90'), a protocol with regex metacharacters, or a malformed pattern object. The catch around new RegExp(regexStr) in remotePatternToRegex fires and the function returns undefined.","commonSituations":" Typos in remotePatterns objects; port given as a range or non-numeric string; assuming remotePatterns supports full regex syntax when it only supports the **. and /* wildcard conventions; copying patterns from next.config.js where semantics differ slightly.","solutions":["Inspect the printed remotePattern JSON and fix field values: protocol like 'https', hostname optionally prefixed with '**.' or '*.', numeric port, pathname using only trailing '/**' or '/*' wildcards.","Move simple hostnames into image.domains instead of remotePatterns when no path/port matching is needed.","Test the pattern locally with a tiny regex rebuild, or just run astro build again to confirm no warning prints and the images are served through the CDN.","If you need regex-level control, verify each segment escapes metacharacters yourself before putting the literal in config."],"exampleFix":"// before (astro.config.mjs)\nimage: {\n  remotePatterns: [{ protocol: 'https', hostname: 'cdn.example.com', port: '80-443' }],\n},\n\n// after\nimage: {\n  remotePatterns: [{ protocol: 'https', hostname: 'cdn.example.com' }],\n},","handlingStrategy":"validation","validationCode":"const isValidRemotePattern = (p: {\n  protocol?: string;\n  hostname?: string;\n  port?: string | number;\n  pathname?: string;\n}): boolean =>\n  (!p.protocol || /^[a-z]+$/i.test(p.protocol)) &&\n  (!p.hostname || /^\\*?\\*?\\.?[a-z0-9.*-]+$/i.test(p.hostname)) &&\n  (p.port === undefined || /^\\d+$/.test(String(p.port))) &&\n  (!p.pathname || /^\\/.*/.test(p.pathname));\n\nconst allPatternsValid = config.image.remotePatterns.every(isValidRemotePattern);","typeGuard":"interface RemotePattern {\n  protocol?: string;\n  hostname?: string;\n  port?: string | number;\n  pathname?: string;\n}\nconst isRemotePattern = (p: unknown): p is RemotePattern =>\n  typeof p === 'object' && p !== null &&\n  Object.keys(p).every((k) => ['protocol', 'hostname', 'port', 'pathname'].includes(k));","tryCatchPattern":null,"preventionTips":["Keep port numeric and omit it when unnecessary.","Use only the supported wildcard forms: '**.' prefix on hostname, trailing '/**' or '/*' on pathname.","Prefer image.domains for plain hostnames and reserve remotePatterns for path/port matching.","Watch build logs for this warning after every image config change; a skipped pattern means unoptimized remote images."],"tags":["netlify","images","remote-patterns","regex","config"],"backgroundTag":"image-remote-pattern-invalid","analyzedSha":"3578d45d34226d63cff3d261c971c221de6794d2","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":"2026-08-18T18:48:03.901Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}