{"record":{"id":"94f10c8041dc8c28","repo":"gitbutlerapp/gitbutler","slug":"unknown-reaction-kind-kind","errorCode":null,"errorMessage":"Unknown reaction kind: {kind}","messagePattern":"Unknown reaction kind: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-github/src/client.rs","lineNumber":2363,"sourceCode":"/// GraphQL's `ReactionContent` enum against the REST kind strings the rest\n/// of the crate speaks, so both APIs report one vocabulary.\nconst REACTION_CONTENTS: [(&str, &str); 8] = [\n    (\"THUMBS_UP\", \"+1\"),\n    (\"THUMBS_DOWN\", \"-1\"),\n    (\"LAUGH\", \"laugh\"),\n    (\"HOORAY\", \"hooray\"),\n    (\"CONFUSED\", \"confused\"),\n    (\"HEART\", \"heart\"),\n    (\"ROCKET\", \"rocket\"),\n    (\"EYES\", \"eyes\"),\n];\n\nfn graphql_reaction_content(kind: &str) -> Result<&'static str> {\n    REACTION_CONTENTS\n        .iter()\n        .find(|(_, rest)| *rest == kind)\n        .map(|(graphql, _)| *graphql)\n        .ok_or_else(|| anyhow::anyhow!(\"Unknown reaction kind: {kind}\"))\n}\n\nfn rest_reaction_kind(content: String) -> String {\n    REACTION_CONTENTS\n        .iter()\n        .find(|(graphql, _)| *graphql == content)\n        .map_or(content, |(_, rest)| (*rest).to_owned())\n}\n\nimpl GraphQlReaction {\n    /// `None` without a database id, which is what callers hold; a made-up 0 would collide.\n    fn into_reaction(self) -> Option<Reaction> {\n        let Some(id) = self.database_id else {\n            tracing::warn!(\"a reaction without a database id was skipped\");\n            return None;\n        };\n        Some(Reaction {\n            id,","sourceCodeStart":2345,"sourceCodeEnd":2381,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-github/src/client.rs#L2345-L2381","documentation":"`graphql_reaction_content` maps a REST reaction kind string (e.g. `\"+1\"`, `\"heart\"`) to GitHub's GraphQL `ReactionContent` enum name by lookup in `REACTION_CONTENTS`; an unknown string fails with this error. It is a strict input-validation failure: the reaction kind is not one the library knows how to translate.","triggerScenarios":"Passing a reaction kind string to a reaction-adding client method that is not in `REACTION_CONTENTS` (typo, wrong casing, newer GitHub reaction type the library predates, or arbitrary user input).","commonSituations":"Hardcoding a reaction kind with a typo (e.g. `\"thumbsup\"` instead of `\"+1\"`); syncing reactions from another forge with different names; GitHub adding a new reaction emoji not yet mapped in the library.","solutions":["Use one of the supported REST kinds from `REACTION_CONTENTS`: `+1`, `-1`, `laugh`, `confused`, `heart`, `hooray`, `rocket`, `eyes`.","Validate/normalize reaction input against the supported list before calling the API.","Upgrade the library if GitHub introduced a new reaction type; add the mapping if you maintain the code.","Map external reaction names to the GitHub kinds explicitly at the boundary of your integration."],"exampleFix":"// before\nclient.add_reaction(pr_number, \"thumbsup\").await?; // unknown kind\n\n// after\nclient.add_reaction(pr_number, \"+1\").await?; // valid REACTION_CONTENTS kind","handlingStrategy":"validation","validationCode":"const KINDS: &[&str] = &[\"+1\", \"-1\", \"laugh\", \"confused\", \"heart\", \"hooray\", \"rocket\", \"eyes\"];\nfn valid_reaction(kind: &str) -> bool { KINDS.contains(&kind) }","typeGuard":null,"tryCatchPattern":"match client.add_reaction(pr_number, kind).await {\n    Err(e) if e.to_string().contains(\"Unknown reaction kind\") => {\n        eprintln!(\"Supported kinds: +1, -1, laugh, confused, heart, hooray, rocket, eyes\");\n    }\n    other => other?,\n}","preventionTips":["Keep a constant list of valid reaction kinds and validate user input against it","Map third-party reaction names to GitHub kinds at your integration boundary","Update the mapping when GitHub adds new reaction types"],"tags":["github","reactions","enum","invalid-input"],"backgroundTag":"invalid-enum-value","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}