leptos-rs/leptos · error
expected string literal
Error message
expected string literal
What it means
In the #[server] macro's argument list, only the FIRST positional argument is allowed (the struct name, and it must be an Ident). If a second bare (non-keyword) identifier argument appears, the parser rejects it with 'expected string literal' because positional slot 2+ only accepts string literals (prefix, encoding, endpoint).
Source
Thrown at server_fn_macro/src/lib.rs:1201
"keyword argument repeated: `impl_deref`",
));
}
impl_deref = Some(stream.parse()?);
} else if key == "protocol" {
if protocol.is_some() {
return Err(syn::Error::new(
key.span(),
"keyword argument repeated: `protocol`",
));
}
protocol = Some(stream.parse()?);
} else {
return Err(lookahead.error());
}
} else {
let value = key_or_value;
if use_key_and_value {
return Err(syn::Error::new(
value.span(),
"positional argument follows keyword argument",
));
}
if arg_pos == 1 {
struct_name = Some(value)
} else {
return Err(syn::Error::new(
value.span(),
"expected string literal",
));
}
}
} else if lookahead.peek(LitStr) {
if use_key_and_value {
return Err(syn::Error::new(
stream.span(),
"If you use keyword arguments (e.g., `name` = \View on GitHub (pinned to 32d20f6c9d)
Solutions
- Remove the extra bare identifier — only one positional argument is allowed.
- If you meant an option, give it its keyword: e.g. encoding = "Url".
- If you meant a string option, pass a string literal such as "api/prefix" instead of an ident.
Example fix
// before #[server(MyServerFn, UrlEnc)] // after #[server(MyServerFn, encoding = "UrlEnc")]
Defensive patterns
Strategy: validation
Validate before calling
// Only the first bare Ident is legal; any other option needs `key = value`.
fn is_positional_ok(args: &[&str]) -> bool {
args.iter().skip(1).all(|a| a.contains('='))
}
assert!(is_positional_ok(&["MyFn", "UrlEnc"])); // fails before compiling Prevention
- Prefer keyword arguments for everything except the struct name
- Quote string options: encoding = "Url", prefix = "api"
- Run cargo check after each attribute edit
When it happens
Trigger: #[server(MyServerFn, SomeExtraIdent)] — a second bare ident after the function/struct name; forgetting the `= value` after an intended keyword so it is parsed as a positional ident; typos like #[server(MyFn, UrlEnc)] instead of encoding = "UrlEnc".
Common situations: Users migrating between the legacy positional form (name, "prefix", "encoding", "endpoint") and keyword form, mixing bare idents where strings were required.
Related errors
- keyword argument repeated: `impl_deref`
- keyword argument repeated: `protocol`
- positional argument follows keyword argument
- If you use keyword arguments (e.g., `name` = Something), the
- unexpected extra argument
AI-assisted analysis of leptos-rs/leptos@32d20f6c9d (2026-09-01).
Data as JSON: /api/errors/c3816db7ca129dee.
Report an issue: GitHub.