astrid-runtime/astrid · error

legacy source entry is group/world writable: {}

Error message

legacy source entry is group/world writable: {}

What it means

Under SourceAccess::OwnerControlled, entries must not be group- or world-writable: if metadata.mode() & 0o022 != 0 the migration fails with PermissionDenied. Group/world-writable files could be modified by other principals, so the owner-controlled guarantee (contents controlled solely by the owner) would not hold.

Source

Thrown at crates/astrid-kernel/src/legacy_migration_barrier/host_fs.rs:786

            io::ErrorKind::InvalidData,
            format!("legacy source contains a special entry: {}", path.display()),
        ));
    }
    #[cfg(unix)]
    {
        use std::os::unix::fs::MetadataExt as _;

        if metadata.uid() != nix::unistd::getuid().as_raw() {
            return Err(io::Error::new(
                io::ErrorKind::PermissionDenied,
                format!(
                    "legacy source entry is not owned by the current user: {}",
                    path.display()
                ),
            ));
        }
        if metadata.mode() & 0o022 != 0 {
            return Err(io::Error::new(
                io::ErrorKind::PermissionDenied,
                format!(
                    "legacy source entry is group/world writable: {}",
                    path.display()
                ),
            ));
        }
        astrid_core::platform_fs::validate_no_extended_acl(path)?;
        Ok(())
    }
    #[cfg(not(unix))]
    {
        validate_private_entry(path, metadata)
    }
}

fn read_regular_file(
    path: &Path,

View on GitHub (pinned to affd8760f4)

Solutions

  1. Tighten permissions: `chmod -R go-w <source>` (e.g. dirs to 0750, files to 0640)
  2. Set a restrictive umask (022 or 077) and recreate/rewrite the offending files
  3. Use SourceAccess::Private if the group/world-writable profile is acceptable in your environment

Example fix

// before: files are group-writable (0664)
let result = snapshot_path_with_access(path, SourceAccess::OwnerControlled);
// Err: legacy source entry is group/world writable: ...

// after: strip group/world write bits, then migrate
// $ chmod -R go-w /home/alice/data
let result = snapshot_path_with_access(path, SourceAccess::OwnerControlled);
Defensive patterns

Strategy: validation

Validate before calling

#[cfg(unix)]
fn assert_not_group_or_world_writable(source: &std::path::Path) -> std::io::Result<()> {
    use std::os::unix::fs::MetadataExt;
    let mut stack = vec![source.to_path_buf()];
    while let Some(dir) = stack.pop() {
        for entry in std::fs::read_dir(&dir)? {
            let path = entry?.path();
            let md = std::fs::symlink_metadata(&path)?;
            if md.mode() & 0o022 != 0 {
                return Err(std::io::Error::new(
                    std::io::ErrorKind::PermissionDenied,
                    format!("group/world writable: {}", path.display()),
                ));
            }
            if md.is_dir() {
                stack.push(path);
            }
        }
    }
    Ok(())
}

Try / catch

match snapshot_path_with_access(source, SourceAccess::OwnerControlled) {
    Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied
        && e.to_string().contains("group/world writable") =>
    {
        eprintln!("fix with: chmod -R go-w <source>");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling the migration API with SourceAccess::OwnerControlled where any file or directory in the source has mode bits 0o020 (group write) or 0o002 (other write) set — e.g. modes like 0664 files, 0775/0777 dirs, or umask-less tools writing 0666 files.

Common situations: Files created with a permissive umask (000) or by tools that force 0666; shared working directories using 0775; defaults of some archive extractors or editors; data copied from FAT/exFAT mounts with permissive modes.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/73e29048fd1b3a4e. Report an issue: GitHub.