gleam-lang/gleam · error
Custom type constructor must have custom type kind
Error message
Custom type constructor must have custom type kind
What it means
After resolving the named type, `check_to_term` looks up the type's constructors via `environment.get_constructors_for_type(&module, &name).expect("Custom type constructor must have custom type kind")`. It panics when the environment has no constructor registration for that type, meaning the type in the check isn't a custom type with registered variants. This is an internal consistency check between type checking and the exhaustiveness environment.
Solutions
- Ensure constructor registration covers all named types used in checks (update `get_constructors_for_type` callers / environment population)
- Check for alias unfolding: resolve type aliases to their underlying custom type before lookup
- Debug-print `module`/`name` at the panic site to find which type lacks registration
- End users: file a compiler bug with the reproducing module
Example fix
// before
.expect("Custom type constructor must have custom type kind")
// after
.unwrap_or_else(|| panic!("no constructors registered for type {}::{} in exhaustiveness environment", module, name)) Defensive patterns
Strategy: validation
Validate before calling
if environment.get_constructors_for_type(&module, &name).is_none() {
return Err(Error::TypeMissingConstructorRegistration { module, name });
} Type guard
fn constructors_registered(env: &Environment, t: &Type) -> bool {
t.named_type_name().map_or(false, |(m, n)| env.get_constructors_for_type(&m, &n).is_some())
} Prevention
- Register constructors for every named type when building the exhaustiveness environment
- Resolve type aliases before lookup
- Log module/name in panic messages for faster triage
When it happens
Trigger: A check references a variable whose named type was never registered in the exhaustiveness `Environment` (e.g. checking against a type that isn't a custom type, or the environment was built without constructors for parameterised/aliased types).
Common situations: Encountered by compiler contributors when types get desugared or aliased before reaching exhaustiveness so the name no longer matches registered constructors, or in fuzzed inputs combining generics with case matching.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- case with no subjects
- Custom type constructor exist for type
- Should be a named type
- wrong number of subject variables for pattern
- wrong number of subjects
AI-assisted analysis of gleam-lang/gleam@15b07c7830 (2026-09-14).
Data as JSON: /api/errors/502cae2f527b8049.
Report an issue: GitHub.
Appendix: source
Thrown at compiler-core/src/exhaustiveness/missing_patterns.rs:186
variable,
elements: elements.clone(),
},
RuntimeCheck::Variant {
index,
fields,
labels,
..
} => {
let (module, name) = variable
.type_
.named_type_name()
.expect("Should be a named type");
let name = self
.environment
.get_constructors_for_type(&module, &name)
.expect("Custom type constructor must have custom type kind")
.variants
.get(*index)
.expect("Custom type constructor exist for type")
.name
.clone();
let fields = fields
.iter()
.enumerate()
.map(|(index, variable)| VariantField {
label: labels.get(&index).cloned(),
variable: variable.clone(),
})
.collect();
Term::Variant {
variable,
name,View on GitHub (pinned to 15b07c7830)