{"record":{"id":"e34cdf7f810c12af","repo":"astrid-runtime/astrid","slug":"keypair-name-name-contains-invalid-chars-only","errorCode":null,"errorMessage":"keypair name {name:?} contains invalid chars; only a-z, 0-9, '-' are allowed","messagePattern":"keypair name (.+?) contains invalid chars; only a-z, 0-9, '-' are allowed","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/keypair.rs","lineNumber":591,"sourceCode":"// ── Misc helpers ─────────────────────────────────────────────────\n\nfn validate_name(name: &str) -> Result<()> {\n    if name.is_empty() {\n        bail!(\"keypair name must not be empty\");\n    }\n    if name.len() > MAX_NAME_LEN {\n        bail!(\n            \"keypair name must be at most {MAX_NAME_LEN} chars (got {})\",\n            name.len()\n        );\n    }\n    // Lowercase letters, digits, dash. Same posture as principal ids;\n    // also avoids path-separator / shell-meta surprises.\n    if !name\n        .chars()\n        .all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '-')\n    {\n        bail!(\"keypair name {name:?} contains invalid chars; only a-z, 0-9, '-' are allowed\");\n    }\n    Ok(())\n}\n\nfn default_name() -> String {\n    let mut bytes = [0u8; 4];\n    SysRng\n        .try_fill_bytes(&mut bytes)\n        .expect(\"OS CSPRNG unavailable while generating default keypair name\");\n    format!(\"key-{}\", hex::encode(bytes))\n}\n\nfn fingerprint_pubkey(hex_pub: &str) -> Result<String> {\n    PublicKeyFingerprint::from_ed25519_hex(hex_pub)\n        .map(PublicKeyFingerprint::into_inner)\n        .map_err(|e| anyhow::anyhow!(\"fingerprint Ed25519 public key: {e}\"))\n}\n","sourceCodeStart":573,"sourceCodeEnd":609,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/keypair.rs#L573-L609","documentation":"validate_name rejects keypair names containing characters outside lowercase ASCII letters, digits, and '-'. This mirrors principal-id formatting and prevents path-separator or shell-metacharacter surprises when the name is used in file paths.","triggerScenarios":"Any keypair command (generate/show/pubkey/delete) or a public-key load / binding record where the name contains uppercase letters, underscores, spaces, dots, slashes, or other non-allowed characters.","commonSituations":"Using snake_case names like \"my_key\"; CamelCase names; names copied with a trailing space; names containing dots or '/'.","solutions":["Rename the keypair using only a-z, 0-9, and '-' (e.g. \"my_key\" -> \"my-key\")","Check for accidental whitespace or invisible characters (trim the input)","Replace '.' or '_' separators with '-'"],"exampleFix":"// before\nrun_show(\"My_Key.prod\")?\n// after\nrun_show(\"my-key-prod\")?","handlingStrategy":"validation","validationCode":"fn valid_keypair_name(name: &str) -> bool {\n    !name.is_empty()\n        && name.chars().all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '-')\n}","typeGuard":"fn is_slug(name: &str) -> bool { !name.is_empty() && name.chars().all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '-') }","tryCatchPattern":"match run_show(&name) {\n    Err(e) if e.to_string().contains(\"invalid chars\") => eprintln!(\"use only a-z, 0-9, '-'\"),\n    other => other,\n}","preventionTips":["Use slug-style names (a-z, 0-9, '-') by convention","Trim inputs to avoid stray spaces","Avoid '_', '.', uppercase, and path characters in names"],"tags":["validation","cli","naming"],"backgroundTag":"invalid-identifier-format","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}