grafana/k6 · critical
unsupported extension type: %T
Error message
unsupported extension type: %T
What it means
ext.Register is the API xk6 extensions use at init time to plug modules into k6. The extensions map only has buckets for the four declared ExtensionType constants (JSExtension, OutputExtension, SecretSourceExtension, SubcommandExtension); any other value — including the zero value — finds no bucket and Register panics with the offending type, crashing the binary at startup.
Source
Thrown at ext/ext.go:68
Name, Path, Version string
Type ExtensionType
Module any
}
func (e Extension) String() string {
return fmt.Sprintf("%s %s, %s [%s]", e.Path, e.Version, e.Name, e.Type)
}
// Register a new extension with the given name and type. This function will
// panic if an unsupported extension type is provided, or if an extension of the
// same type and name is already registered.
func Register(name string, typ ExtensionType, mod any) {
mx.Lock()
defer mx.Unlock()
exts, ok := extensions[typ]
if !ok {
panic(fmt.Sprintf("unsupported extension type: %T", typ))
}
if _, ok := exts[name]; ok {
panic(fmt.Sprintf("extension already registered: %s", name))
}
path, version := extractModuleInfo(mod)
exts[name] = &Extension{
Name: name,
Type: typ,
Module: mod,
Path: path,
Version: version,
}
}
// Get returns all extensions of the specified type.View on GitHub (pinned to 93accf6570)
Solutions
- Use only the exported constants: ext.JSExtension, ext.OutputExtension, ext.SecretSourceExtension, ext.SubcommandExtension
- If compiling against older k6, guard with a build tag or version check rather than a raw constant
- Fail fast in tests: call ext.Get(type) in a unit test so bad values panic in CI, not at user startup
- If you genuinely need a new type, add it to the enum in ext/ext.go and rebuild rather than casting
Example fix
// before
func init() { ext.Register("k6/x/myext", ext.ExtensionType(0), &MyExt{}) } // panics: unsupported extension type
// after
func init() { ext.Register("k6/x/myext", ext.JSExtension, &MyExt{}) } Defensive patterns
Strategy: validation
Validate before calling
// Go, in the extension package
var validTypes = map[ext.ExtensionType]bool{
ext.JSExtension: true, ext.OutputExtension: true,
ext.SecretSourceExtension: true, ext.SubcommandExtension: true,
}
func register(name string, typ ext.ExtensionType, mod any) {
if !validTypes[typ] { panic(fmt.Sprintf("bad extension type %d for %s", typ, name)) }
ext.Register(name, typ, mod)
} Type guard
// Go
func isValidExtType(t ext.ExtensionType) bool { return t >= ext.JSExtension && t <= ext.SubcommandExtension } Prevention
- Only use the exported ext constants; never cast integers to ExtensionType
- Add a unit test that exercises every Register call in the extension so bad values fail in CI
- Avoid 0 as a placeholder — the zero value has no bucket and always panics
When it happens
Trigger: An extension's init() calls ext.Register('k6/x/foo', myType, mod) where myType is a cast like ext.ExtensionType(0), ext.ExtensionType(99), or a locally-defined constant outside the enum. Since ExtensionType is an untyped-able uint8, accidental integer literals compile fine and panic at runtime during binary startup.
Common situations: Writing a new xk6 extension and passing an untyped constant 0; copy-pasting a Register call and forgetting to change the type; code written against a newer k6 that adds an extension type, compiled into an older k6 where that bucket does not exist; refactor leaving a stale type value.
Related errors
- extension already registered: %s
- Error while parsing selector `${selector}` - cannot use ${op
- unhandled extension type: %s
- Error while parsing selector `${selector}` - selector cannot
- "${attr}" attribute is only supported for roles: ${roles.sli
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/7e2de13f7e943ad8.
Report an issue: GitHub.