gleam-lang/gleam · error · TypeError

UTF-codepoint pattern matching is not supported

Error message

UTF-codepoint pattern matching is not supported

What it means

Gleam compile error (TypeError::OptionNotSupportedForTarget): when type-checking bit array segments in pattern position that use utf8_codepoint, utf16_codepoint, or utf32_codepoint while compiling for the JavaScript target. The guard mode == TypeOptionsMode::Pattern && target == Target::JavaScript fires because the JS codegen cannot destructure UTF codepoint segments in patterns (it can still construct them in expressions); the compiler rejects the segment with UnsupportedOption::UtfCodepointPattern and points at the offending option.

Source

Thrown at compiler-core/src/bit_array.rs:115

fn type_options<TypedValue>(
    input_options: &[BitArrayOption<TypedValue>],
    mode: TypeOptionsMode,
    must_have_size: bool,
    target: Target,
) -> Result<Arc<Type>, Error>
where
    TypedValue: GetLiteralValue,
{
    use BitArrayOption::*;

    let mut categories = SegmentOptionCategories::new();
    // Basic category checking
    for option in input_options {
        match option {
            Utf8Codepoint { .. } | Utf16Codepoint { .. } | Utf32Codepoint { .. }
                if mode == TypeOptionsMode::Pattern && target == Target::JavaScript =>
            {
                return err(
                    ErrorType::OptionNotSupportedForTarget {
                        target,
                        option: UnsupportedOption::UtfCodepointPattern,
                    },
                    option.location(),
                );
            }

            Bytes { .. }
            | Int { .. }
            | Float { .. }
            | Bits { .. }
            | Utf8 { .. }
            | Utf16 { .. }
            | Utf32 { .. }
            | Utf8Codepoint { .. }
            | Utf16Codepoint { .. }
            | Utf32Codepoint { .. } => {

View on GitHub (pinned to 3e3c5ddc08)

Solutions

  1. Rewrite the pattern without codepoint options: match the remaining bytes (e.g. <<rest:bytes>>) and decode with bit_array.to_string / string functions afterwards
  2. Match on Gleam String values directly where possible, since Gleam strings are UTF-8 and support pattern matching via case
  3. Keep such modules on the Erlang target by setting target = "erlang" if JS support is not required

Example fix

// before (panics only at compile time on the JavaScript target)
// gleam.toml: target = "javascript"
pub fn first_codepoint(s: BitArray) {
  case s {
    <<codepoint:utf8_codepoint, rest:bits>> -> Ok(#(codepoint, rest))
    _ -> Error(Nil)
  }
}

// after: match bytes, decode as UTF-8 string instead
pub fn first_codepoint(s: BitArray) {
  case s {
    <<first:bytes-size(1), rest:bits>> ->
      case bit_array.to_string(<<first, rest:bits>>) {
        Ok(string) -> string_pop_grapheme(string)
        Error(Nil) -> Error(Nil)
      }
    _ -> Error(Nil)
  }
}
Defensive patterns

Strategy: validation

Validate before calling

# catch target-specific bit array rejections before shipping: check both targets in CI
gleam check --target erlang && gleam check --target javascript

Prevention

When it happens

Trigger: Writing a case pattern like '<<c:utf8_codepoint, rest:bits>>' and building/checking with target = "javascript" in gleam.toml or --target javascript. The same pattern compiles fine on the Erlang target.

Common situations: Porting string/binary parsing code originally written for the Erlang target to JavaScript; sharing parsing modules between targets; following Erlang-style binary-matching idioms.

Related errors


AI-assisted analysis of gleam-lang/gleam@3e3c5ddc08 (2026-08-20). Data as JSON: /api/errors/03ecdf7a03ef1688. Report an issue: GitHub.