{"record":{"id":"a1c3e9c28b22b034","repo":"grafana/k6","slug":"extension-already-registered-s","errorCode":null,"errorMessage":"extension already registered: %s","messagePattern":"extension already registered: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"ext/ext.go","lineNumber":72,"sourceCode":"\nfunc (e Extension) String() string {\n\treturn fmt.Sprintf(\"%s %s, %s [%s]\", e.Path, e.Version, e.Name, e.Type)\n}\n\n// Register a new extension with the given name and type. This function will\n// panic if an unsupported extension type is provided, or if an extension of the\n// same type and name is already registered.\nfunc Register(name string, typ ExtensionType, mod any) {\n\tmx.Lock()\n\tdefer mx.Unlock()\n\n\texts, ok := extensions[typ]\n\tif !ok {\n\t\tpanic(fmt.Sprintf(\"unsupported extension type: %T\", typ))\n\t}\n\n\tif _, ok := exts[name]; ok {\n\t\tpanic(fmt.Sprintf(\"extension already registered: %s\", name))\n\t}\n\n\tpath, version := extractModuleInfo(mod)\n\n\texts[name] = &Extension{\n\t\tName:    name,\n\t\tType:    typ,\n\t\tModule:  mod,\n\t\tPath:    path,\n\t\tVersion: version,\n\t}\n}\n\n// Get returns all extensions of the specified type.\nfunc Get(typ ExtensionType) map[string]*Extension {\n\tmx.RLock()\n\tdefer mx.RUnlock()\n","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/ext/ext.go#L54-L90","documentation":"ext.Register keeps a per-type map keyed by extension name. Registering a second extension of the same type under an already-used name trips this panic during init, before any test runs — the registry deliberately refuses silent overrides so two different modules cannot masquerade under one import path.","triggerScenarios":"Two xk6 extensions in one binary both calling ext.Register(\"k6/x/mymod\", ext.JSExtension, ...); an extension registered from two init() paths (e.g. the package linked twice via different import paths after a rename); a fork reusing an existing extension's name; output extensions colliding on a name like \"custom\".","commonSituations":"k6 binary built with two extensions where one is a vendored fork/older copy of the other (common after xk6 build flag drift); module moved to a new path but old path still imported somewhere; accidental double registration when a file is duplicated in the extensions tree; CI building with stale extension pins.","solutions":["Give each extension a unique name — conventionally its full import path (k6/x/...), which makes collisions structurally unlikely","Remove the stale copy: go mod tidy / clean the xk6 build pins so only one version of the module is linked","If the duplicate comes from a vendored fork, rename the fork's registered name in its init()","Rebuild the binary and verify with k6 version / k6 inspect that each extension appears once"],"exampleFix":"// before (two packages both do)\nfunc init() { ext.Register(\"k6/x/queue\", ext.JSExtension, &Q{}) } // second one panics at startup\n\n// after (fork renamed)\nfunc init() { ext.Register(\"k6/x/queue-fork\", ext.JSExtension, &Q{}) }","handlingStrategy":"validation","validationCode":"// Go, guard before registering\nfunc registerOnce(name string, typ ext.ExtensionType, mod any) {\n  if _, dup := ext.Get(typ)[name]; dup { // note: panics on bad typ; validate it first\n    panic(fmt.Sprintf(\"extension %q already registered - rename this one\", name))\n  }\n  ext.Register(name, typ, mod)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Register under the full import path (k6/x/...) — globally unique by construction","go mod tidy after adding/removing extensions so stale duplicates drop out","When vendoring a fork, rename its registered module name immediately","Inspect registration output (k6 version / k6 inspect) in CI to catch double registrations before users do"],"tags":["extensions","xk6","panic","startup","duplicate-registration"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}