{"record":{"id":"c7ac3c81eed659de","repo":"astrid-runtime/astrid","slug":"legacy-secret-source-remains-after-migration","errorCode":null,"errorMessage":"legacy secret source remains after migration: {}","messagePattern":"legacy secret source remains after migration: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/legacy_migration_barrier/host_fs.rs","lineNumber":110,"sourceCode":"                \"legacy secrets root is not a regular directory: {}\",\n                root.display()\n            ),\n        ));\n    }\n    astrid_core::platform_fs::validate_private_directory(root)?;\n    astrid_core::platform_fs::verify_no_redirects(root)?;\n    let entries = fs::read_dir(root)\n        .map_err(io::Error::other)?\n        .collect::<Result<Vec<_>, _>>()\n        .map_err(io::Error::other)?;\n    for entry in entries {\n        if entry.file_name() == \"__host__\" {\n            continue;\n        }\n        let path = entry.path();\n        let snapshot = snapshot_path(&path)?;\n        if snapshot.entries != 0 {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                format!(\n                    \"legacy secret source remains after migration: {}\",\n                    path.display()\n                ),\n            ));\n        }\n        if allow_empty_cleanup {\n            retire_empty_directory(&path)?;\n        } else {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                format!(\n                    \"legacy secret source reappeared after cut-over: {}\",\n                    path.display()\n                ),\n            ));\n        }","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/legacy_migration_barrier/host_fs.rs#L92-L128","documentation":"After migration, every legacy secret source directory (except `__host__`) must be empty — its snapshot entry count must be 0. A non-empty snapshot means the migration failed to consume all secret files, and the library raises `InvalidData` naming the path.","triggerScenarios":"Calling `ensure_legacy_secret_aliases` during post-migration verification when `snapshot_path(path).entries != 0` for a legacy source directory.","commonSituations":"New secret files appeared in the legacy directory during migration (running app wrote a credential); some files were skipped due to names not matching expected patterns; a partially failed prior migration left files behind.","solutions":["Investigate the named directory, move/import any remaining secret files, and re-run migration.","Ensure no processes write new secrets into the legacy root during migration.","Manually clear the legacy directory once its contents are accounted for."],"exampleFix":"# before: legacy dir still has leftovers\nls legacy-secrets/api/  # token.txt still present\n# after: migrate leftovers then re-run\nastrid migrate --include legacy-secrets/api/token.txt","handlingStrategy":"validation","validationCode":"fn legacy_fully_migrated(legacy_root: &std::path::Path) -> bool {\n    std::fs::read_dir(legacy_root).map(|rd| rd.filter_map(Result::ok)\n        .filter(|e| e.file_name() != \"__host__\")\n        .all(|e| std::fs::read_dir(e.path()).map(|mut d| d.next().is_none()).unwrap_or(false)))\n    .unwrap_or(false)\n}","typeGuard":null,"tryCatchPattern":"match ensure_legacy_secret_aliases(root, ...) {\n    Err(e) if e.to_string().contains(\"remains after migration\") => {\n        let dir = extract_path(&e); // from message\n        eprintln!(\"leftover secrets in {dir}; import them and re-run\");\n        return Err(e.into());\n    }\n    other => other,\n}","preventionTips":["Ensure no processes write new secrets into the legacy root during migration.","Verify all expected secret filenames are handled by the migration patterns.","Run migration once to completion; avoid partial/interrupted runs."],"tags":["migration","verification","filesystem"],"backgroundTag":"internal-invariant-violation","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}