Gleam Let Assert
The let assert expression tells Gleam to match a pattern and panic if the match fails. It is a tool for situations where you are absolutely certain a value has a specific shape — and want the program to crash loudly if it does not.
Standard let vs let assert
Standard let — only works with irrefutable patterns:
──────────────────────────────────────────────────
let x = 42 // always succeeds — x matches any value
let #(a, b) = #(1, 2) // always succeeds — structure is fixed
let assert — works with any pattern, panics if it fails:
──────────────────────────────────────────────────
let assert Ok(value) = might_return_error()
// If result is Error(...), the program panics
When to Use let assert
Use let assert when you want to extract a value from a pattern that could theoretically fail — but you know from context that it will not. Common uses include test setup, startup configuration loading, and initializing known-good data.
let assert Use Cases
──────────────────────────────────────────────────
✓ Reading config values that must exist at startup
✓ Parsing data in test code where you control input
✓ Extracting from Result when failure means a bug
✗ Production code handling user input (use case instead)
Extracting from Option
import gleam/list
let numbers = [10, 20, 30]
let assert Ok(first) = list.first(numbers)
// first = 10
// If numbers were [], list.first returns Error(Nil)
// and the program would panic with a clear message
let assert Flow Diagram
──────────────────────────────────────────────────
list.first([10, 20, 30]) returns Ok(10)
let assert Ok(first) = Ok(10)
↓
Pattern Ok(first) matches Ok(10)? YES
↓
first = 10 ✓
If it returned Error(Nil):
let assert Ok(first) = Error(Nil)
↓
Pattern Ok(first) matches Error(Nil)? NO
↓
PANIC — program crashes with a message
Extracting from Result
import gleam/int
// Parsing a string we wrote ourselves — we know it's valid
let assert Ok(port) = int.parse("8080")
// port = 8080
let assert in Tests
Test code often uses let assert because test input is controlled — you wrote it yourself:
pub fn parse_config_test() {
let assert Ok(config) = load_config("test_config.json")
assert config.port == 8080
assert config.host == "localhost"
}If load_config fails during a test, a panic with a clear error message is exactly what you want — it stops the test immediately and tells you what went wrong.
let assert vs case
Comparison: let assert vs case
──────────────────────────────────────────────────
// With case (safe, handles both outcomes):
case int.parse(user_input) {
Ok(n) -> use_number(n)
Error(Nil) -> show_error("Not a valid number")
}
// With let assert (panics on Error):
let assert Ok(n) = int.parse(user_input)
use_number(n)
The case version handles bad input gracefully. The let assert version crashes if the input is invalid. Choose case for user-provided data. Choose let assert only when failure truly represents a programming error, not a user error.
Tuple Destructuring with let assert
let data = #(200, "Success", True)
// Standard let works because the pattern is irrefutable:
let #(code, message, ok) = data
// code = 200, message = "Success", ok = True
// let assert works the same way for simple tuples:
let assert #(200, msg, _) = data
// msg = "Success"
// Panics if data is not #(200, ...)
Panic Messages
When let assert fails, Gleam prints a clear panic message that includes the file name and line number:
Panic Output Example
──────────────────────────────────────────────────
error: Assertion failed
→ src/main.gleam:14
Pattern `Ok(n)` did not match value `Error(Nil)`
The program crashed here so you can fix the issue
before it causes silent failures elsewhere.
Summary
let assert Quick Reference
──────────────────────────────────────────────────
Syntax: let assert Pattern = expression
Use when:
• You control the input and know the pattern matches
• A non-match would be a programming bug, not user error
• Setting up test data
Avoid when:
• Handling user input or external data
• Production code where graceful error handling is needed
→ Use case expression instead
let assert is a deliberate choice: you are saying "I guarantee this matches — crash loudly if I am wrong." That loud crash is useful during development. In production systems handling untrusted input, a well-structured case expression is always the safer path.
