risingwavelabs/risingwave · error
expected string literal
Error message
expected string literal
What it means
Same `get_value()` closure as the "expected literal" check, but one level deeper: the value must be a literal AND a string literal (`syn::Lit::Str`). Integers, booleans, chars, or byte strings after an attribute key produce this spanned error.
Source
Thrown at src/expr/macro/src/parse.rs:65
} else {
args.split(',').map(|s| s.trim().to_owned()).collect()
};
parsed.ret = ret.trim().to_owned();
parsed.is_table_function = is_table_function;
if input.parse::<Token![,]>().is_err() {
return Ok(parsed);
}
let metas = input.parse_terminated(syn::Meta::parse, Token![,])?;
for meta in metas {
let get_value = || {
let kv = meta.require_name_value()?;
let syn::Expr::Lit(lit) = &kv.value else {
return Err(Error::new(kv.value.span(), "expected literal"));
};
let syn::Lit::Str(lit) = &lit.lit else {
return Err(Error::new(kv.value.span(), "expected string literal"));
};
Ok(lit.value())
};
if meta.path().is_ident("batch_fn") {
parsed.batch_fn = Some(get_value()?);
} else if meta.path().is_ident("state") {
parsed.state = Some(get_value()?);
} else if meta.path().is_ident("init_state") {
parsed.init_state = Some(get_value()?);
} else if meta.path().is_ident("prebuild") {
parsed.prebuild = Some(get_value()?);
} else if meta.path().is_ident("type_infer") {
parsed.type_infer = Some(get_value()?);
} else if meta.path().is_ident("generic") {
parsed.generic = Some(get_value()?);
} else if meta.path().is_ident("volatile") {
parsed.volatile = true;
} else if meta.path().is_ident("deprecated") || meta.path().is_ident("internal") {View on GitHub (pinned to 6469eb736d)
Solutions
- Wrap the value in double quotes so it is a Rust string literal: `type_infer = "infer_type"`.
- Check the expected format of each key in existing `#[function]` usages and match it.
- If passing a type, express it as a string the macro can parse, e.g. `state = "MyState"`.
Example fix
// before
#[function("avg(int4)", state = MyState)]
// after
#[function("avg(int4)", state = "MyState")] Defensive patterns
Strategy: validation
Validate before calling
// Every value for batch_fn/state/init_state/prebuild/type_infer/generic must be a quoted string:
fn is_string_literal_attr(v: &str) -> bool { v.starts_with('"') && v.ends_with('"') }
assert!(is_string_literal_attr("\"MyState\"")); Prevention
- Quote every attribute value: `state = "MyState"`, `type_infer = "infer_fn"`.
- Never pass bare identifiers, numbers, or chars to these keys.
- Compare against existing #[function] usages when unsure of the expected format.
When it happens
Trigger: Writing `#[function("sig(int4)", type_infer = 42)]`, `state = true`, `prebuild = 'c'`, or any non-string literal for keys `batch_fn`, `state`, `init_state`, `prebuild`, `type_infer`, or `generic`.
Common situations: Developers passing type identifiers or numeric flags instead of quoted type/function-name strings when declaring function attributes.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- expected literal
- invalid property: {:?}
- You can't use the macro on this type
- Expected #[serde_prefix_all(skip)]
- type inference function cannot be automatically derived. You
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/8647e2c04e980719.
Report an issue: GitHub.