risingwavelabs/risingwave · critical
failed to lookup type matrix: unknown type
Error message
failed to lookup type matrix: unknown type: {} What it means
`lookup_matrix` in src/expr/macro/src/types.rs resolves type names (int4, varchar, ...) against a fixed TYPE_MATRIX table to obtain data/array/owned/ref types. Any type string that does not match a row (after `[]`→anyarray, `struct*`→struct, `void`→int4 normalization) panics with "failed to lookup type matrix: unknown type: {}".
Solutions
- Use exact matrix names: int2/int4/int8, float4/float8, varchar, bytea, boolean, decimal, date, time, timestamp, timestamptz, interval, jsonb, etc.
- If the type genuinely doesn't exist, add a new row to TYPE_MATRIX in src/expr/macro/src/types.rs.
- Remember `[]`, `struct<...>`, and `void` are auto-normalized; other aliases are not — normalize your string yourself if needed.
Example fix
// before - `int` is not in the type matrix
#[function("my_add(int, int)")]
// after
#[function("my_add(int4, int4)")] Defensive patterns
Strategy: validation
Validate before calling
const MATRIX_NAMES: &[&str] = &["boolean","int2","int4","int8","int256","float4","float8","decimal","serial","date","time","timestamp","timestamptz","interval","varchar","bytea","jsonb","variant","vector","anyarray","struct","anymap","any"];
fn type_known(ty: &str) -> bool {
let t = if ty.ends_with("[]") { "anyarray" }
else if ty.starts_with("struct") { "struct" }
else if ty == "void" { "int4" } else { ty };
MATRIX_NAMES.contains(&t)
}
assert!(type_known("int4"));
assert!(!type_known("int")); Prevention
- Use only names from TYPE_MATRIX in signature strings; `int`/`text`/`string` are NOT valid — use int4/varchar.
- Note the automatic rewrites: `T[]` -> anyarray, `struct<...>` -> struct, `void` -> int4; anything else must match exactly.
- When adding a new scalar type, add its row to TYPE_MATRIX in the same PR that uses it in signatures.
When it happens
Trigger: Declaring `#[function]` or `#[aggregate]` signatures using unsupported or misspelled type names such as `int`, `integer`, `text`, `string`, `float`, or a custom type not present in TYPE_MATRIX; this panic propagates through data_type/array_type/owned_type/ref_type/is_primitive.
Common situations: Developers writing SQL-ish names instead of the internal short names (int4 vs int, varchar vs text); using a newly introduced type before adding it to the matrix; case mismatches (`INT4`).
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- expect accumulate function
- expect fn
- expect `impl Iterator` in return type
- expected literal
- Expected #[serde_prefix_all(skip)]
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/9a0affed837734f8.
Report an issue: GitHub.
Appendix: source
Thrown at src/expr/macro/src/types.rs:87
fn lookup_matrix(mut ty: &str, idx: usize) -> &str {
if ty.ends_with("[]") {
ty = "anyarray";
} else if ty.starts_with("struct") {
ty = "struct";
} else if ty == "void" {
// XXX: we don't support void type yet.
// replace it with int for now.
ty = "int4";
}
let s = TYPE_MATRIX.trim().lines().find_map(|line| {
let mut parts = line.split_whitespace();
if parts.next() == Some(ty) {
Some(parts.nth(idx - 1).unwrap())
} else {
None
}
});
s.unwrap_or_else(|| panic!("failed to lookup type matrix: unknown type: {}", ty))
}
/// Expands a type wildcard string into a list of concrete types.
pub fn expand_type_wildcard(ty: &str) -> Vec<&str> {
match ty {
"*" => TYPE_MATRIX
.trim()
.lines()
.map(|l| l.split_whitespace().next().unwrap())
.filter(|l| *l != "any")
.collect(),
"*int" => vec!["int2", "int4", "int8"],
"*float" => vec!["float4", "float8"],
_ => vec![ty],
}
}
/// Computes the minimal compatible type between a pair of data types.View on GitHub (pinned to 6469eb736d)