GraphiteEditor/Graphite · error · syn::Error
value for key {k} was already given
Error message
value for key {k} was already given What it means
The `#[hint(key = "value")]` helper attribute feeds the `Hint` derive a key→string map (mouse-button tooltips etc.). Keys are collected across every #[hint] attribute on the item into one map, and each key must appear exactly once; the first occurrence wins silently, and every subsequent occurrence raises this compile-time error pointing at the duplicate literal.
Source
Thrown at proc-macros/src/hint.rs:24
fn parse_hint_helper_attrs(attrs: &[Attribute]) -> syn::Result<(Vec<LitStr>, Vec<LitStr>)> {
fold_error_iter(
attrs
.iter()
.filter(|a| a.path().get_ident().is_some_and(|i| i == "hint"))
.map(|attr| attr.parse_args::<AttrInnerKeyStringMap>()),
)
.and_then(|v: Vec<AttrInnerKeyStringMap>| {
fold_error_iter(AttrInnerKeyStringMap::multi_into_iter(v).map(|(k, mut v)| match v.len() {
0 => panic!("internal error: a key without values was somehow inserted into the hashmap"),
1 => {
let single_val = v.pop().unwrap();
Ok((LitStr::new(&k.to_string(), Span::call_site()), single_val))
}
_ => {
// the first value is ok, the other ones should error
let after_first = v.into_iter().skip(1);
// this call to fold_error_iter will always return Err with a combined error
fold_error_iter(after_first.map(|lit| Err(syn::Error::new(lit.span(), format!("value for key {k} was already given"))))).map(|_: Vec<()>| unreachable!())
}
}))
})
.map(|v| v.into_iter().unzip())
}
pub fn derive_hint_impl(input_item: TokenStream2) -> syn::Result<TokenStream2> {
let input = syn::parse2::<DeriveInput>(input_item)?;
let ident = input.ident;
match input.data {
Data::Enum(data) => {
let variants = data.variants.iter().map(|var: &Variant| two_segment_path(ident.clone(), var.ident.clone())).collect::<Vec<_>>();
let hint_result = fold_error_iter(data.variants.into_iter().map(|var: Variant| parse_hint_helper_attrs(&var.attrs)));
hint_result.map(|hints: Vec<(Vec<LitStr>, Vec<LitStr>)>| {View on GitHub (pinned to c507b35645)
Solutions
- Find the duplicated key named in the error message and delete all but one `key = "value"` pair.
- If two hints were intentional, rename the second occurrence to a distinct key.
- After fixing, run `cargo check` again — only one duplicate is reported per pass, so repeat until clean.
Example fix
// before
#[derive(Hint)]
enum Tool {
#[hint(lmb = "Draw", lmb = "Erase")]
Brush,
}
// after
#[derive(Hint)]
enum Tool {
#[hint(lmb = "Draw")]
Brush,
} Defensive patterns
Strategy: validation
Prevention
- Use each hint key at most once per item, including across stacked #[hint] attributes.
- After merge conflicts in hint lists, grep the variant for repeated keys before compiling.
- Run `cargo check` after editing hint attributes — the error names the key and spans the duplicate literal.
When it happens
Trigger: Writing the same key twice in one attribute (`#[hint(rmb = "foo", rmb = "bar")]`), or repeating a key across stacked attributes (`#[hint(a = "1")] #[hint(a = "2")]`) on the same enum variant or struct. Only the extras after the first are errored.
Common situations: Merge conflicts resolved by keeping both sides of a hint list, copy-pasting a hint attribute and editing only the value while forgetting the key, or tooling that concatenates hint attributes.
Related errors
- Failed to parse node_fn attributes: {e}
- command functions may not have attributes; anything that doe
- Failed to parse input type for #[implementation(...)]. Expec
- Expected `->` arrow after input type in #[implementations(..
- Failed to parse output type for #[implementation(...)]. Expe
AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16).
Data as JSON: /api/errors/1cec1e51cbe26237.
Report an issue: GitHub.