{"record":{"id":"660de85dd78e2b6e","repo":"warpdotdev/warp","slug":"multiple-api-keys-match-key-identifier-specif","errorCode":null,"errorMessage":"Multiple API keys match '{key_identifier}'; specify the key by UID","messagePattern":"Multiple API keys match '(.+?)'; specify the key by UID","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"app/src/ai/agent_sdk/api_key.rs","lineNumber":345,"sourceCode":"\n    if io::stdin().is_terminal() {\n        return match Select::new(\n            &format!(\"Multiple API keys match '{key_identifier}'. Select a key to expire:\"),\n            matches,\n        )\n        .prompt()\n        {\n            Ok(key) => Ok(Some(key)),\n            Err(InquireError::OperationCanceled | InquireError::OperationInterrupted) => Ok(None),\n            Err(err) => Err(err.into()),\n        };\n    }\n    println!(\"Multiple API keys match '{key_identifier}':\");\n    for key in matches {\n        println!(\"  {key}\");\n    }\n\n    Err(anyhow!(\n        \"Multiple API keys match '{key_identifier}'; specify the key by UID\"\n    ))\n}\n\n#[derive(Debug, Clone, Serialize)]\nstruct CreatedApiKeyInfo {\n    raw_api_key: String,\n    api_key: ApiKeyInfo,\n}\n\n#[derive(Debug, Clone, Serialize)]\nstruct ExpiredApiKeyInfo {\n    key_uid: String,\n    expired: bool,\n}\n\nfn sort_api_keys(\n    keys: &mut [ApiKeyInfo],","sourceCodeStart":327,"sourceCodeEnd":363,"githubUrl":"https://github.com/warpdotdev/warp/blob/e72fd7aacbbb2236d9b3be2aad7e7178fe94b4bc/app/src/ai/agent_sdk/api_key.rs#L327-L363","documentation":"`resolve_api_key_identifier` found two or more API keys whose name equals the identifier. In a TTY it shows an interactive `Select` picker; with non-interactive stdin it prints every match and errors, requiring the unique UID instead. Name-based selection is intentionally refused when it would be ambiguous.","triggerScenarios":"Running `warp api-key expire <name>` where more than one listed key shares that name AND stdin is not a terminal, so the interactive selector cannot be shown.","commonSituations":"Automation scripts referring to keys by a reused name like 'ci-key'; teams creating same-named keys over time; piping commands so the picker never appears; CI jobs using names instead of UIDs.","solutions":["Copy the UID of the intended key from the printed list (or `warp api-key list`) and pass that instead","Run the command in a real terminal and choose from the interactive selector","Rename or expire duplicate-named keys so the name becomes unique"],"exampleFix":"# before\nwarp api-key expire ci-key < /dev/null\n# after\nwarp api-key list   # note the uid\nwarp api-key expire <uid-from-list>","handlingStrategy":"validation","validationCode":"fn unique_name_match<'a>(keys: &'a [ApiKeyInfo], name: &str) -> Option<&'a ApiKeyInfo> {\n    let mut matches = keys.iter().filter(|k| k.name == name);\n    let first = matches.next()?;\n    matches.next().is_none().then_some(first)\n}\n// When None, fall back to UID lookup instead of letting the CLI error.","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Give API keys unique names at creation time","Use UIDs in all non-interactive tooling","Prune duplicate-named keys during rotation"],"tags":["api-key","cli","ambiguity","interactive","identifier"],"backgroundTag":null,"analyzedSha":"e72fd7aacbbb2236d9b3be2aad7e7178fe94b4bc","analyzedAt":"2026-08-16T08:27:25.381Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}