gleam-lang/gleam · error

Type has already checked to be valid

Error message

Type has already checked to be valid

What it means

This panic fires in the Gleam compiler's field-access inference when a match on the inferred Type reaches an arm (Fn, Var, Tuple) that the earlier type-checking stages should have rejected as invalid for field access. The compiler asserts an internal invariant: by this point the type is guaranteed to be a Record with accessors. Hitting it means some other part of the type checker let an invalid type slip through.

Solutions

  1. Report the case to the Gleam compiler repository with the code snippet that triggers it
  2. Check whether the code compiles with an older/newer Gleam version to identify a regression
  3. Simplify the offending expression — often annotating the value with an explicit record type sidesteps the inference hole
  4. Update the compiler to the latest patch, since unreachable-arm panics are usually fixed quickly

Example fix

// before (user code triggering inference hole)
let f = fn(x) { x }
f.field
// after
let f = fn(x) { x }
// f is a function; do not access fields on it — use a record instead
Defensive patterns

Strategy: try-catch

Validate before calling

// Cannot validate; ensure field access is only used on record-typed values
// assert inference: value must not be Fn/Var/Tuple before accessor lookup

Try / catch

// Panics abort the process; no catch. Verify with a fixed compiler version:
// run `gleam build` on the snippet; if it panics, reduce and file an issue.

Prevention

When it happens

Trigger: Accessing a field/position on a value whose inferred type is a function, type variable, or tuple after inference concludes; this indicates a bug in the exhaustiveness or inference logic upstream, not user error directly.

Common situations: Compiler bugs triggered by unusual code — e.g. accessing accessors on a value of polymorphic type where unification failed to concretize a Type::Var, or a regression after changing inference rules.

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/4c2d19eb5039f0ad. Report an issue: GitHub.

Appendix: source

Thrown at compiler-core/src/type_/expression.rs:2978

                        } => self
                            .environment
                            .importable_modules
                            .get(module)
                            .and_then(|module| module.accessors.get(name))
                            .filter(|accessors_map| {
                                accessors_map.publicity.is_importable()
                                    || module == &self.environment.current_module
                            })
                            .and_then(|accessors_map| {
                                Some((
                                    accessors_map.type_.clone(),
                                    accessors_map
                                        .positional_accessors(inferred_variant.unwrap_or(0))?,
                                ))
                            }),

                        Type::Fn { .. } | Type::Var { .. } | Type::Tuple { .. } => {
                            panic!("Type has already checked to be valid")
                        }
                    }
                    .expect("Variant has already checked to be valid");

                // Positional fields must always be defined before any labelled fields.
                // As such, we expect that field indices 0..(positional_fields.length)
                // all correspond to positional fields. If this is not the case, then the
                // user currently has a mistake in the definition of their custom type.
                //
                // However, we do not want to show an error here, because it would be
                // confusing for the programmer. They can already see the error at the type
                // definition site.
                let type_ = if let Some(type_) = positional_fields.get(index as usize) {
                    type_.clone()
                } else {
                    continue;
                };

View on GitHub (pinned to 15b07c7830)