#1946·astrid

Owner-only path checks have no migration: 421 pre-existing entries fail boot, one per attempt

Author: jvsteinerCreated Sep 15, 2026Updated Sep 15, 2026

Summary

The private-path checks require permissions to be exactly 0o700 for directories and 0o600 for files, but nothing in the upgrade path relaxes or repairs modes written by earlier releases. An ~/.astrid created by an older version fails the check, and because the check aborts on the first offending path, the operator gets one filename per boot attempt with no idea how many remain. On my install that was 421 entries.

Error: Failed to boot Kernel: private directory is not owner-only: /Users/jamie/.astrid/cow
Error: Failed to boot Kernel: private file is not owner-only: /Users/jamie/.astrid/cow/.DS_Store
Error: Failed to boot Kernel: private file is not owner-only: /Users/jamie/.astrid/home/claude-code/.local/log/a2a-capsule/2026-08-29.log

Mechanism

crates/astrid-core/src/platform_fs.rs:468 tests exact equality, not a permissive mask:

rust
if metadata.permissions().mode() & 0o777 != 0o700 {
    return Err(io::Error::new(
        io::ErrorKind::PermissionDenied,
        format!("private directory is not owner-only: {}", path.display()),
    ));
}

and platform_fs.rs:520 likewise for files:

rust
if metadata.st_mode & 0o777 != 0o600 {
    return Err(io::Error::new(
        io::ErrorKind::PermissionDenied,
        format!("private file is not owner-only: {}", path.display()),
    ));
}

The tightening is correct — these hold secrets, keys and principal state, and I am not arguing the check should be loosened. The problem is that it was introduced without a migration, and it is enforced during boot one path at a time. Directories created at 0755 and log files created at 0644 by earlier releases are now fatal, and recovery is a guessing game unless the operator thinks to run find ~/.astrid -perm +077 themselves.

Note the file rule is exactly 0o600, so a file at 0o700 also fails. Anything shipped executable inside the private tree would need care.

Reproduction Steps

  1. Use an ~/.astrid created by an earlier release (mine dates to 2026-05-24) where directories are 0755 and log files are 0644.
  2. Upgrade to 2026.9.2 via astrid update.
  3. Run astrid start. Boot fails naming one path.
  4. Fix that one path. Run astrid start again. Boot fails naming the next path.
  5. Repeat. In my case 421 entries needed fixing before boot progressed.

chmod -R go-rwx ~/.astrid resolves all of them at once, but the operator has to work that out unaided.

Expected Behavior

  • Repair modes as part of the upgrade: walk the private tree once and chmod entries the runtime owns to 0700/0600, the same way other layout migrations run at boot.
  • Failing that, validate the whole tree in one pass and report every offending path, plus the exact remedy (chmod -R go-rwx ~/.astrid), instead of aborting on the first one.
  • A pre-flight in astrid doctor that reports non-conforming modes would let this be caught before the daemon refuses to start.

Environment

  • OS: macOS 15.6 (Darwin 24.6.0), arm64
  • Astrid: 2026.9.2, installed via astrid update
  • Source: astrid-runtime/astrid @ 73661c9b (Cargo version 0.10.4)
  • ~/.astrid first created 2026-05-24
  • 421 files/directories failed the owner-only check

Logs / Backtrace

$ find ~/.astrid \( -type f -o -type d \) -perm +077 | wc -l
     421

$ find ~/.astrid -type d -not -perm 700
/Users/jamie/.astrid/cow
/Users/jamie/.astrid/secrets/claude-code
/Users/jamie/.astrid/secrets/default
/Users/jamie/.astrid/etc/profiles
/Users/jamie/.astrid/var/update
/Users/jamie/.astrid/var/state.db
...

Consecutive boot attempts, each surfacing exactly one path:

Error: Failed to boot Kernel: private directory is not owner-only: /Users/jamie/.astrid/cow
Error: Failed to boot Kernel: private file is not owner-only: /Users/jamie/.astrid/cow/.DS_Store
Error: Failed to boot Kernel: private file is not owner-only: /Users/jamie/.astrid/home/claude-code/.local/log/a2a-capsule/2026-08-29.log