{"record":{"id":"f07df53e560b9641","repo":"astrid-runtime/astrid","slug":"capsule-version-is-not-valid-semver","errorCode":null,"errorMessage":"capsule '{}': version '{}' is not valid semver","messagePattern":"capsule '(.+?)': version '(.+?)' is not valid semver","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/distro/validate.rs","lineNumber":163,"sourceCode":"        // `tag`. (Git-ref installs remain available via the standalone\n        // `astrid capsule install` command.)\n        if cap.branch.is_some() || cap.rev.is_some() {\n            anyhow::bail!(\n                \"capsule '{}': branch/rev require building from source and are not allowed in a \\\n                 distro manifest — pin a released `version` or `tag` (git-ref installs are \\\n                 available via `astrid capsule install`).\",\n                cap.name,\n            );\n        }\n        let version = cap.version.trim();\n        if cap.version != version {\n            anyhow::bail!(\n                \"capsule '{}': version must not contain surrounding whitespace\",\n                cap.name\n            );\n        }\n        if !version.is_empty() && Version::parse(version).is_err() {\n            anyhow::bail!(\n                \"capsule '{}': version '{}' is not valid semver\",\n                cap.name,\n                cap.version\n            );\n        }\n        let tag = cap.tag.as_deref().map(str::trim);\n        if let Some(raw_tag) = cap.tag.as_deref()\n            && raw_tag != raw_tag.trim()\n        {\n            anyhow::bail!(\n                \"capsule '{}': tag must not contain surrounding whitespace\",\n                cap.name\n            );\n        }\n        if matches!(tag, Some(\"\")) {\n            anyhow::bail!(\"capsule '{}': tag must not be empty\", cap.name);\n        }\n        if version.is_empty() && tag.is_none() {","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/distro/validate.rs#L145-L181","documentation":"After rejecting whitespace, validate_manifest parses the capsule's version with `semver::Version::parse` (a concrete version, not a requirement) and bails if it is not valid semver. Empty versions are skipped here because a separate check requires either version or tag.","triggerScenarios":"A `[[capsules]]` entry with a non-empty `version` like `\"1.2\"`, `\"v1.2.0\"`, `\"1.2.0-beta\"` is actually valid — invalid ones are `\"1.2\"`, `\"v1.0.0\"`, `\"latest\"`, `\"1.2.3.4\"`, or date strings.","commonSituations":"Using a two-component version (`1.2`) where semver demands three; prefixing with `v` like a git tag; putting a tag name or `latest` into the version field instead of the `tag` field.","solutions":["Rewrite the version as full semver `MAJOR.MINOR.PATCH` (optionally with prerelease/build, e.g. `1.2.0-rc.1`).","Remove a leading `v` — `v1.2.0` belongs in `tag`, not `version`.","If you meant a git tag, set `tag = \"v1.2.0\"` and clear `version` (or keep both consistent)."],"exampleFix":"# before\n[[capsules]]\nname = \"http\"\nversion = \"v1.2\"\n\n# after\n[[capsules]]\nname = \"http\"\nversion = \"1.2.0\"","handlingStrategy":"validation","validationCode":"for cap in &manifest.capsules {\n    let v = cap.version.trim();\n    if !v.is_empty() && semver::Version::parse(v).is_err() {\n        panic!(\"capsule '{}': version '{}' is not valid semver\", cap.name, cap.version);\n    }\n}","typeGuard":"fn is_exact_semver(s: &str) -> bool {\n    semver::Version::parse(s.trim()).is_ok()\n}","tryCatchPattern":"if let Err(e) = validate_manifest(&manifest) {\n    if e.to_string().contains(\"is not valid semver\") {\n        eprintln!(\"use MAJOR.MINOR.PATCH: {e}\");\n    }\n}","preventionTips":["Always write three-component versions (1.2.0, not 1.2 or v1.2)","Put git tag strings (with leading v) in `tag`, not `version`","Parse-check versions with a semver library in CI"],"tags":["cli","manifest","semver","validation"],"backgroundTag":"invalid-argument-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"}