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

  1. Ensure constructor registration covers all named types used in checks (update `get_constructors_for_type` callers / environment population)
  2. Check for alias unfolding: resolve type aliases to their underlying custom type before lookup
  3. Debug-print `module`/`name` at the panic site to find which type lacks registration
  4. 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

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


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)