{"record":{"id":"eacce3257a63c8cb","repo":"astrid-runtime/astrid","slug":"keypair-name-must-be-at-most-max-name-len-chars","errorCode":null,"errorMessage":"keypair name must be at most {MAX_NAME_LEN} chars (got {})","messagePattern":"keypair name must be at most (.+?) chars \\(got (.+?)\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/keypair.rs","lineNumber":580,"sourceCode":"        match read_meta(&paths) {\n            Ok(meta) => out.push(KeyEntry { name, meta }),\n            Err(e) => {\n                tracing::warn!(name = %name, error = %e, \"skipping unreadable keypair meta\");\n            },\n        }\n    }\n    out.sort_by(|a, b| a.name.cmp(&b.name));\n    Ok(out)\n}\n\n// ── 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","sourceCodeStart":562,"sourceCodeEnd":598,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/keypair.rs#L562-L598","documentation":"validate_name enforces the keypair naming rules before any keypair operation. A keypair name longer than MAX_NAME_LEN bytes is rejected with this error, keeping names compatible with principal-id length limits and filesystem/socket path constraints.","triggerScenarios":"Calling `aos keypair generate`, `show`, `pubkey`, or `delete` (or loading a public key / recording a binding) with a name whose byte length exceeds MAX_NAME_LEN.","commonSituations":"Copy-pasting a long host or project name as the keypair name; generating names programmatically by concatenating prefix + timestamp/uuid; CI configs embedding full hostnames.","solutions":["Shorten the keypair name to at most MAX_NAME_LEN chars","Use `aos keypair generate` without --name to get a short auto-generated default name","If a long label is needed, store the long identifier separately and reference the short keypair name"],"exampleFix":"// before\nrun_generate(\"my-team-production-cluster-eu-west-1-keypair-2026\")?\n// after\nrun_generate(\"prod-eu1\")?","handlingStrategy":"validation","validationCode":"fn valid_keypair_name(name: &str) -> bool {\n    const MAX_NAME_LEN: usize = 64; // match the CLI's MAX_NAME_LEN\n    !name.is_empty() && name.len() <= MAX_NAME_LEN\n}","typeGuard":"fn is_short_enough(name: &str, max: usize) -> bool { name.len() <= max }","tryCatchPattern":"match run_generate(&name) {\n    Err(e) if e.to_string().contains(\"at most\") => eprintln!(\"name too long, pick a shorter name\"),\n    other => other,\n}","preventionTips":["Keep keypair names short and mnemonic; store long labels elsewhere","Validate length in scripts before invoking the CLI","Use the auto-generated default name when a custom name isn't required"],"tags":["validation","cli","naming"],"backgroundTag":"value-out-of-range","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"}