{"record":{"id":"0d7a4a548f3d9718","repo":"astrid-runtime/astrid","slug":"legacy-capsule-directory-is-not-a-regular-director","errorCode":null,"errorMessage":"legacy capsule directory is not a regular directory: {}","messagePattern":"legacy capsule directory is not a regular directory: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-capsule-install/src/storage/migration.rs","lineNumber":109,"sourceCode":"    store: &Arc<RuntimePrincipalStore>,\n    home: &astrid_core::dirs::AstridHome,\n    principal: &PrincipalId,\n    workspace_targets: &[std::path::PathBuf],\n) -> anyhow::Result<LegacyCapsuleMigrationReport> {\n    let uid = store\n        .principal_directory()\n        .uid_for(principal)\n        .with_context(|| format!(\"resolve durable uid for principal {principal}\"))?;\n    let native = home.principal_home(principal).capsules_dir();\n    let metadata = match fs::symlink_metadata(&native) {\n        Ok(metadata) => metadata,\n        Err(error) if error.kind() == io::ErrorKind::NotFound => {\n            return Ok(LegacyCapsuleMigrationReport::default());\n        },\n        Err(error) => return Err(error).with_context(|| format!(\"inspect {}\", native.display())),\n    };\n    if metadata.file_type().is_symlink() || !metadata.is_dir() {\n        bail!(\n            \"legacy capsule directory is not a regular directory: {}\",\n            native.display()\n        );\n    }\n    astrid_core::platform_fs::verify_no_redirects(&native)\n        .with_context(|| format!(\"verify legacy capsule root {}\", native.display()))?;\n    let mut children = read_dir_sorted(&native)?;\n    let mut report = LegacyCapsuleMigrationReport::default();\n    let registry = store.capsules();\n    let owner = StateOwner::Principal(uid);\n    for (target, target_metadata) in children.drain(..) {\n        if target_metadata.file_type().is_symlink() || !target_metadata.is_dir() {\n            bail!(\n                \"legacy capsule entry is not a regular directory: {}\",\n                target.display()\n            );\n        }\n        let id = target","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-capsule-install/src/storage/migration.rs#L91-L127","documentation":"migrate_native_capsules_with_report inspects the legacy native capsule directory (~/.astrid/native or similar) before migrating. If that root path exists but is a symlink or not a regular directory, migration aborts instead of migrating through an unexpected filesystem object.","triggerScenarios":"The native capsule directory is a symlink (e.g. pointed at Dropbox/Network drive or another location), a plain file was created at that path, or a mount/hardlink oddity replaced the directory.","commonSituations":"User symlinked their config/data directory into a sync folder; backup tool restored the path as a file; automount points presenting a non-directory node.","solutions":["Remove the symlink/file at the native path and restore a real directory","Move the real data into the expected directory location directly","Point the home/config setting at the actual directory instead of symlinking","Restore the directory from backup with directory type preserved"],"exampleFix":"# before\nln -s ~/Dropbox/astrid-native ~/.astrid/native\n# after\nmv ~/Dropbox/astrid-native/* ~/.astrid/native/  # real directory, no symlink","handlingStrategy":"validation","validationCode":"use std::fs;\nfn native_root_is_plain_dir(p: &Path) -> Result<(), String> {\n    let md = fs::symlink_metadata(p).map_err(|e| e.to_string())?;\n    if md.file_type().is_symlink() { return Err(\"symlink\".into()); }\n    if !md.is_dir() { return Err(\"not a directory\".into()); }\n    Ok(())\n}","typeGuard":"fn is_plain_directory(p: &std::path::Path) -> bool {\n    match std::fs::symlink_metadata(p) {\n        Ok(md) => md.is_dir() && !md.file_type().is_symlink(),\n        Err(_) => false,\n    }\n}","tryCatchPattern":"match migrate_native_capsules(home, store) {\n    Err(e) if e.to_string().contains(\"not a regular directory\") => {\n        eprintln!(\"fix the native capsule path (remove symlink/file) and retry\");\n    }\n    other => other?,\n}","preventionTips":["Do not symlink the native capsule directory into sync folders or network drives","Keep backups that preserve directory types","Check the home path configuration if the root unexpectedly exists as a file","Run migration before installing any symlinked dev capsules"],"tags":["filesystem","migration","symlink","path-validation"],"backgroundTag":"path-is-not-a-directory","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}