{"record":{"id":"b22af5b9c0cacda3","repo":"astrid-runtime/astrid","slug":"distro-id-is-invalid-must-match-a-z-a-z0","errorCode":null,"errorMessage":"distro.id '{}' is invalid (must match ^[a-z][a-z0-9-]*$)","messagePattern":"distro\\.id '(.+?)' is invalid \\(must match \\^\\[a-z\\]\\[a-z0-9-\\]\\*\\$\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/distro/validate.rs","lineNumber":88,"sourceCode":"/// - Variable references in capsule env resolve to defined variables\n/// - Requires version strings are valid semver requirements\n#[allow(\n    clippy::too_many_lines,\n    reason = \"flat sequence of independent validation checks; \\\n              inlining keeps the full ruleset auditable in one place\"\n)]\npub(crate) fn validate_manifest(manifest: &DistroManifest) -> anyhow::Result<()> {\n    // Schema version.\n    if manifest.schema_version != SCHEMA_VERSION {\n        anyhow::bail!(\n            \"unsupported schema-version {} (expected {SCHEMA_VERSION})\",\n            manifest.schema_version,\n        );\n    }\n\n    // Distro ID format.\n    if !is_valid_id(&manifest.distro.id) {\n        anyhow::bail!(\n            \"distro.id '{}' is invalid (must match ^[a-z][a-z0-9-]*$)\",\n            manifest.distro.id,\n        );\n    }\n\n    // Distro version is valid semver.\n    if semver::Version::parse(&manifest.distro.version).is_err() {\n        anyhow::bail!(\n            \"distro.version '{}' is not valid semver\",\n            manifest.distro.version,\n        );\n    }\n\n    // astrid-version is valid semver requirement (if set).\n    if let Some(ref av) = manifest.distro.astrid_version\n        && semver::VersionReq::parse(av).is_err()\n    {\n        anyhow::bail!(\"distro.astrid-version '{av}' is not a valid semver requirement\");","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/distro/validate.rs#L70-L106","documentation":"validate_manifest enforces that distro.id matches ^[a-z][a-z0-9-]*$ — a lowercase identifier usable in file paths, package names, and URLs. An ID violating this pattern is rejected because it could break path handling or downstream naming rules.","triggerScenarios":"Distro.toml whose [distro] id contains uppercase letters, underscores, spaces, digits at the start, or is empty.","commonSituations":"Naming the distro after a product with capitals (\"MyDistro\"); using snake_case out of habit; leading digits copied from a version number.","solutions":["Rename the distro id to lowercase letters/digits/hyphens starting with a letter (e.g. my-distro)","Replace underscores with hyphens and drop invalid characters","Move a human-readable title to a separate metadata field if one exists"],"exampleFix":"// before\n// [distro]\n// id = \"My_Distro1\"\n// after\n// [distro]\n// id = \"my-distro1\"","handlingStrategy":"validation","validationCode":"fn is_valid_id(id: &str) -> bool {\n    !id.is_empty()\n        && id.chars().next().map_or(false, |c| c.is_ascii_lowercase())\n        && id.chars().all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '-')\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Enforce the id regex in lint/CI for Distro.toml","Use hyphen-case naming conventions org-wide","Validate the manifest right after editing it"],"tags":["validation","naming","identifier","manifest"],"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-14T05:17:10.506Z"}