astrid-runtime/astrid · error
opaque asset path must be a directory: {}
Error message
opaque asset path must be a directory: {} What it means
The signed channel pointer must name its release metadata asset exactly 'astrid-<version>-release.toml', derived from the pointer's own version. This ensure! fails when metadata_asset diverges from that canonical naming scheme, so the client would fetch a manifest it cannot bind to this pointer.
Source
Thrown at crates/astrid-build/src/archiver.rs:39
let mut files = Vec::new();
for name in OPAQUE_ASSET_DIRS {
let root = base_dir.join(name);
let metadata = match fs::symlink_metadata(&root) {
Ok(metadata) => metadata,
Err(error) if error.kind() == std::io::ErrorKind::NotFound => continue,
Err(error) => {
return Err(error)
.with_context(|| format!("Failed to inspect asset path: {}", root.display()));
},
};
if metadata.file_type().is_symlink() {
anyhow::bail!(
"opaque capsule asset directories cannot be symlinks: {}",
root.display()
);
}
if !metadata.is_dir() {
anyhow::bail!("opaque asset path must be a directory: {}", root.display());
}
let mut pending = vec![root];
while let Some(dir) = pending.pop() {
for entry in fs::read_dir(&dir)
.with_context(|| format!("Failed to read asset directory: {}", dir.display()))?
{
let entry = entry?;
let path = entry.path();
let file_type = entry.file_type()?;
if file_type.is_symlink() {
anyhow::bail!(
"opaque capsule assets cannot be symlinks: {}",
path.display()
);
}
if file_type.is_dir() {
pending.push(path);
} else if file_type.is_file() {View on GitHub (pinned to affd8760f4)
Solutions
- Set release.metadata_asset to exactly "astrid-<version>-release.toml" using the canonical version from the pointer.
- Regenerate the signed pointer with the release tooling so all derived fields are consistent.
- Re-sign and re-upload the pointer, then re-run parse_channel.
Example fix
# before version = "1.2.3" metadata_asset = "astrid-release.toml" # after version = "1.2.3" metadata_asset = "astrid-1.2.3-release.toml"
Defensive patterns
Strategy: validation
Validate before calling
fn metadata_asset_ok(version: &str, asset: &str) -> bool {
asset == format!("astrid-{version}-release.toml")
} Try / catch
if let Err(e) = parse_channel(&bytes, channel, now) {
if e.to_string().contains("metadata asset is invalid") { /* fix asset name and re-sign */ }
return Err(e.into());
} Prevention
- Derive metadata_asset from the version programmatically
- Lint derived fields before signing
- Regenerate pointers with tooling, not by hand
When it happens
Trigger: validate_pointer (via parse_channel or enforce_continuity) sees a ChannelPointer whose release.metadata_asset is not the string format!("astrid-{version}-release.toml") for the canonical version.
Common situations: Renamed or vendored manifest asset in a hand-maintained channel file; a tool from an older naming convention; typo in the asset field; pointer regenerated for a different version but asset name left stale.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- WASM binary not found at {}
- opaque capsule asset directories cannot be symlinks: {}
- capsule archive already contains {PROVENANCE_FILE}
- capsule archive contains duplicate entry '{requested}'
- distro.id '{}' is invalid (must match ^[a-z][a-z0-9-]*$)
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/075f81cf5178058b.
Report an issue: GitHub.