{"record":{"id":"3e987e2423e31c9c","repo":"astrid-runtime/astrid","slug":"capsule-source-has-no-capsule-toml","errorCode":null,"errorMessage":"capsule source has no Capsule.toml","messagePattern":"capsule source has no Capsule\\.toml","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-capsule-install/src/storage.rs","lineNumber":751,"sourceCode":"\nfn authority_capsule_id(authority: &[u8]) -> anyhow::Result<String> {\n    let authority: InstalledAuthority =\n        serde_json::from_slice(authority).context(\"decode authority receipt for package id\")?;\n    if authority.capsule_id.is_empty() {\n        bail!(\"authority receipt has an empty capsule id\");\n    }\n    Ok(authority.capsule_id)\n}\n\n/// Build a deterministic gzip/tar package from a checked directory.\npub fn canonical_capsule_archive(source_dir: &Path) -> anyhow::Result<Vec<u8>> {\n    let mut entries = Vec::new();\n    collect_entries(source_dir, source_dir, &mut entries)?;\n    if !entries\n        .iter()\n        .any(|(path, _)| path == Path::new(\"Capsule.toml\"))\n    {\n        bail!(\"capsule source has no Capsule.toml\");\n    }\n    entries.sort_by(|left, right| left.0.cmp(&right.0));\n\n    let output = Vec::new();\n    let encoder = GzEncoder::new(output, Compression::default());\n    let mut builder = Builder::new(encoder);\n    builder.mode(tar::HeaderMode::Deterministic);\n    for (relative, metadata) in entries {\n        append_entry(&mut builder, source_dir, &relative, &metadata)?;\n    }\n    let encoder = builder\n        .into_inner()\n        .context(\"finish canonical capsule tar stream\")?;\n    encoder\n        .finish()\n        .context(\"finish canonical capsule gzip stream\")\n}\n","sourceCodeStart":733,"sourceCodeEnd":769,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-capsule-install/src/storage.rs#L733-L769","documentation":"Raised by canonical_capsule_archive when the collected entries of the source directory do not include a Capsule.toml at the archive root. Capsule.toml is the mandatory manifest; without it the archive would not be a valid capsule package, so the library refuses to build it.","triggerScenarios":"Calling canonical_capsule_archive (directly or via publish_directory_package or canonical_legacy_archive) on a directory that lacks Capsule.toml at its root, or where the manifest was excluded by naming/meta filtering; collect_entries gathered only other files.","commonSituations":"Running publish from the wrong directory (parent or subdirectory instead of the capsule root); manifest renamed (capsule.toml on case-sensitive FS) or deleted; pointing the publisher at a build-output dir that doesn't contain the manifest.","solutions":["Run the archive/publish command from the directory that directly contains Capsule.toml.","Check the file exists with the exact name/casing `Capsule.toml` (case-sensitive on Linux).","Restore the manifest if deleted, e.g. from version control, then retry the publish."],"exampleFix":"# before: publishing from the wrong directory\npublish ./my-capsule/src\n\n# after: publish the capsule root\npublish ./my-capsule  # contains Capsule.toml","handlingStrategy":"validation","validationCode":"fn ensure_capsule_manifest(dir: &Path) -> Result<(), String> {\n    let p = dir.join(\"Capsule.toml\");\n    if p.is_file() { Ok(()) } else { Err(format!(\"missing {}\", p.display())) }\n}","typeGuard":"fn is_capsule_root(dir: &Path) -> bool {\n    dir.join(\"Capsule.toml\").is_file()\n}","tryCatchPattern":"if !Path::new(\"Capsule.toml\").exists() {\n    eprintln!(\"run from the capsule root, not {}\", env::current_dir()?.display());\n    std::process::exit(1);\n}","preventionTips":["Always publish from the directory containing Capsule.toml","Watch the exact casing `Capsule.toml` on case-sensitive filesystems","Commit Capsule.toml so it can't be silently deleted"],"tags":["missing-manifest","capsule","packaging"],"backgroundTag":"file-not-found","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"}