astrid-runtime/astrid · error
durable capsule archive contains a link or special file
Error message
durable capsule archive contains a link or special file
What it means
read_archive_files found a tar entry whose type is neither a regular file nor a directory — e.g. a symlink, hardlink, fifo, or device node. The library refuses such entries because links and special files can redirect reads/writes outside the capsule content and have no place in a deterministic capsule archive.
Source
Thrown at crates/astrid-capsule-install/src/storage.rs:377
let mut files = std::collections::BTreeMap::new();
let mut directories = std::collections::BTreeSet::new();
for entry in archive.entries().context("read durable capsule archive")? {
let mut entry = entry.context("read durable capsule archive entry")?;
let path = entry.path().context("read durable capsule archive path")?;
if path.is_absolute()
|| path.components().any(|component| {
matches!(
component,
std::path::Component::ParentDir | std::path::Component::RootDir
)
})
{
bail!("durable capsule archive contains unsafe path");
}
let entry_type = entry.header().entry_type();
if !entry_type.is_dir() && !entry_type.is_file() {
bail!("durable capsule archive contains a link or special file");
}
let name = path
.to_str()
.ok_or_else(|| anyhow::anyhow!("durable capsule archive path is not UTF-8"))?
.replace('\\', "/");
if files.contains_key(&name) || directories.contains(&name) {
bail!("durable capsule archive contains duplicate path {name}");
}
if entry_type.is_dir() {
if !directories.insert(name) {
bail!("durable capsule archive contains duplicate directory path");
}
continue;
}
let mut bytes = Vec::new();
entryView on GitHub (pinned to affd8760f4)
Solutions
- Rebuild the archive dereferencing symlinks (--dereference / follow-links) so only regular files are stored.
- Remove symlinks/special files from the source tree before packaging (vendor or inline their content).
- Configure the archiver to skip non-regular entry types.
- Reject the archive and ask the publisher to fix their packaging.
Example fix
// before: tar preserves symlinks tar -czf capsule.tgz -C src . # keeps symlinks // after: dereference links when archiving tar -czf capsule.tgz -C src --dereference .
Defensive patterns
Strategy: validation
Validate before calling
let entry_type = entry.header().entry_type();
if !entry_type.is_dir() && !entry_type.is_file() {
return Err("archive entry is a link or special file");
} Type guard
fn is_regular_entry(h: &tar::Header) -> bool {
let t = h.entry_type();
t.is_file() || t.is_dir()
} Try / catch
match read_verified_durable_package_for_owner(&store, owner, id).await {
Ok(pkg) => pkg,
Err(e) if e.to_string().contains("link or special file") => {
// rebuild archive with --dereference or without symlinks
},
Err(e) => return Err(e),
} Prevention
- Archive with --dereference (or follow symlinks in code) so only regular files are stored.
- Keep capsule source trees symlink-free; vendor linked content.
- Inspect the archive (tar -tvf) for 'l' type entries before publishing.
When it happens
Trigger: read_archive_files on an archive containing symlink/hardlink/device entries; entry_type().is_dir() and is_file() both false triggers the bail.
Common situations: Source tree containing symlinks (node_modules links, docs symlinks) archived with tar's default link preservation; packaging on Unix where symlinks are common; archives produced by tools that include metadata nodes.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- capsule archive contains a link or special file {name}
- capsule archive contains an unsafe path {}
- durable capsule archive contains unsafe path
- malicious shuttle detected: links are not allowed ('{}')
- authenticated AstridFS.app is redirected or not a directory
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/57007822f0f1734b.
Report an issue: GitHub.