{"id":"c0f94006fa56ef54","repo":"evanw/esbuild","slug":"invalid-origin-s","errorCode":null,"errorMessage":"Invalid origin: %s","messagePattern":"Invalid origin: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/api/serve_other.go","lineNumber":770,"sourceCode":"\t\t\tserveOptions.Servedir = absPath\n\t\t} else {\n\t\t\treturn ServeResult{}, fmt.Errorf(\"Invalid serve path: %s\", serveOptions.Servedir)\n\t\t}\n\t}\n\n\t// Validate the \"fallback\" path\n\tif serveOptions.Fallback != \"\" {\n\t\tif absPath, ok := ctx.realFS.Abs(serveOptions.Fallback); ok {\n\t\t\tserveOptions.Fallback = absPath\n\t\t} else {\n\t\t\treturn ServeResult{}, fmt.Errorf(\"Invalid fallback path: %s\", serveOptions.Fallback)\n\t\t}\n\t}\n\n\t// Validate the CORS origins\n\tfor _, origin := range serveOptions.CORS.Origin {\n\t\tif star := strings.IndexByte(origin, '*'); star >= 0 && strings.ContainsRune(origin[star+1:], '*') {\n\t\t\treturn ServeResult{}, fmt.Errorf(\"Invalid origin: %s\", origin)\n\t\t}\n\t}\n\n\t// Stuff related to the output directory only matters if there are entry points\n\toutdirPathPrefix := \"\"\n\tif len(ctx.args.entryPoints) > 0 {\n\t\t// Don't allow serving when builds are written to stdout\n\t\tif ctx.args.options.WriteToStdout {\n\t\t\twhat := \"entry points\"\n\t\t\tif len(ctx.args.entryPoints) == 1 {\n\t\t\t\twhat = \"an entry point\"\n\t\t\t}\n\t\t\treturn ServeResult{}, fmt.Errorf(\"Cannot serve %s without an output path\", what)\n\t\t}\n\n\t\t// Compute the output path prefix\n\t\tif serveOptions.Servedir != \"\" && ctx.args.options.AbsOutputDir != \"\" {\n\t\t\t// Make sure the output directory is contained in the \"servedir\" directory","sourceCodeStart":752,"sourceCodeEnd":788,"githubUrl":"https://github.com/evanw/esbuild/blob/6ff1d8b0d8c134e867a397eef39702a223ebef9e/pkg/api/serve_other.go#L752-L788","documentation":"Returned by internalContext.Serve when a CORS origin in serveOptions.CORS.Origin contains more than one '*' wildcard. esbuild allows a single '*' per origin pattern (for subdomain matching like 'https://*.example.com') but rejects multiple wildcards because they are ambiguous and not meaningfully matchable. The check scans for the first '*' and errors if another '*' appears after it.","triggerScenarios":"Calling ctx.Serve() with CORS.Origin containing an entry like 'https://*.*.com' or 'https://*.example.*'. The check at serve_other.go:769 finds a second '*' after the first and returns the error.","commonSituations":"Trying to allow multiple subdomain levels with '*.example.*'; copy-pasting an overly broad CORS pattern; misunderstanding CORS wildcard semantics; a config that joins several patterns with '*' separators.","solutions":["Use at most one '*' per origin, e.g. 'https://*.example.com'.","If you need to allow multiple domains, list each origin as a separate array entry.","Replace multi-wildcard patterns with explicit origins or a single leading '*'.","Validate each CORS origin has zero or one '*' before calling Serve()."],"exampleFix":"// before\nctx.Serve({ CORS: { Origin: ['https://*.example.*'] } }); // two wildcards\n\n// after\nctx.Serve({ CORS: { Origin: ['https://*.example.com', 'https://example.*'] } });","handlingStrategy":"validation","validationCode":"function validOrigins(origins) {\n  return origins.every(o => (o.match(/\\*/g) || []).length <= 1);\n}\nif (!validOrigins(serveOpts.CORS.Origin)) throw new Error('CORS origin has multiple wildcards');","typeGuard":"function isValidOrigin(o) { return typeof o === 'string' && (o.match(/\\*/g) || []).length <= 1; }","tryCatchPattern":"try { await ctx.Serve({ CORS: { Origin } }); } catch (e) { if (/Invalid origin/.test(e.message)) { Origin = Origin.map(fixMultiWildcard); /* retry */ } throw e; }","preventionTips":["Use at most one '*' per CORS origin.","List each allowed domain as a separate array entry.","Validate origins before calling Serve().","Prefer explicit origins over broad wildcards."],"tags":["esbuild","serve","cors","configuration","validation"],"analyzedSha":"6ff1d8b0d8c134e867a397eef39702a223ebef9e","analyzedAt":"2026-08-03T19:42:38.433Z","schemaVersion":2}