{"record":{"id":"9cc032194d021b02","repo":"evanw/esbuild","slug":"invalid-packages","errorCode":null,"errorMessage":"Invalid packages","messagePattern":"Invalid packages","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"pkg/api/api_impl.go","lineNumber":239,"sourceCode":"func validateASCIIOnly(value Charset) bool {\n\tswitch value {\n\tcase CharsetDefault, CharsetASCII:\n\t\treturn true\n\tcase CharsetUTF8:\n\t\treturn false\n\tdefault:\n\t\tpanic(\"Invalid charset\")\n\t}\n}\n\nfunc validateExternalPackages(value Packages) bool {\n\tswitch value {\n\tcase PackagesDefault, PackagesBundle:\n\t\treturn false\n\tcase PackagesExternal:\n\t\treturn true\n\tdefault:\n\t\tpanic(\"Invalid packages\")\n\t}\n}\n\nfunc validateTreeShaking(value TreeShaking, bundle bool, format Format) bool {\n\tswitch value {\n\tcase TreeShakingDefault:\n\t\t// If we're in an IIFE then there's no way to concatenate additional code\n\t\t// to the end of our output so we assume tree shaking is safe. And when\n\t\t// bundling we assume that tree shaking is safe because if you want to add\n\t\t// code to the bundle, you should be doing that by including it in the\n\t\t// bundle instead of concatenating it afterward, so we also assume tree\n\t\t// shaking is safe then. Otherwise we assume tree shaking is not safe.\n\t\treturn bundle || format == FormatIIFE\n\tcase TreeShakingFalse:\n\t\treturn false\n\tcase TreeShakingTrue:\n\t\treturn true\n\tdefault:","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/evanw/esbuild/blob/f6058f8364fe7ab91ca57a83e02577ed74c9cae4/pkg/api/api_impl.go#L221-L257","documentation":"validateExternalPackages (pkg/api/api_impl.go:239) panics when Packages is not PackagesDefault(0), PackagesBundle(1), or PackagesExternal(2). The returned bool tells the resolver whether `node_modules` dependencies are inlined or treated as external imports; an undefined value would break module resolution, so esbuild aborts. Called from validateBuildOptions.","triggerScenarios":"Assigning BuildOptions.Packages from a raw integer or a deserialized value outside 0..2. The panic fires during option validation, before any resolution.","commonSituations":"Bundlers/wrappers that expose a numeric `--packages` mode, version skew between JS API and Go core after an upgrade, or hand-written config using an invented constant name.","solutions":["Use api.PackagesDefault (default), api.PackagesBundle, or api.PackagesExternal only.","Bounds-check externally sourced integers against 0..2 before casting.","Represent the option as a string in serialized config and map to the constant at load.","Pin and rebuild against one esbuild version across your stack."],"exampleFix":"// before\nopts := api.BuildOptions{Packages: api.Packages(3), Bundle: true}\n\n// after\nopts := api.BuildOptions{Packages: api.PackagesDefault, Bundle: true}","handlingStrategy":"validation","validationCode":"func checkPackages(p api.Packages) error {\n    switch p {\n    case api.PackagesDefault, api.PackagesBundle, api.PackagesExternal:\n        return nil\n    }\n    return fmt.Errorf(\"invalid packages %d (want 0..2)\", uint8(p))\n}","typeGuard":"func isValidPackages(p api.Packages) bool {\n    switch p {\n    case api.PackagesDefault, api.PackagesBundle, api.PackagesExternal:\n        return true\n    }\n    return false\n}","tryCatchPattern":null,"preventionTips":["Use PackagesDefault; it applies esbuild's recommended behavior per platform.","Map CLI-style strings to constants rather than ordinals.","Bounds-check integers from external sources to 0..2.","Keep wrappers and the core on the same esbuild version."],"tags":["esbuild","config","validation","panic","packages","enum"],"backgroundTag":null,"analyzedSha":"f6058f8364fe7ab91ca57a83e02577ed74c9cae4","analyzedAt":"2026-08-09T18:37:22.223Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}