{"record":{"id":"321d2d120ed8483b","repo":"Hmbown/CodeWhale","slug":"task-record-identity-differs-from-its-path","errorCode":null,"errorMessage":"Task record identity differs from its path","messagePattern":"Task record identity differs from its path","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/task_manager.rs","lineNumber":3170,"sourceCode":"            let entry = entry?;\n            let path = entry.path();\n            if path.extension().is_none_or(|ext| ext != \"json\") {\n                continue;\n            }\n            let content = fs::read_to_string(&path)\n                .with_context(|| format!(\"Failed to read task file {}\", path.display()))?;\n            let task: TaskRecord = serde_json::from_str(&content)\n                .with_context(|| format!(\"Failed to parse task file {}\", path.display()))?;\n            if task.schema_version > CURRENT_TASK_SCHEMA_VERSION {\n                bail!(\n                    \"Task schema v{} is newer than supported v{}\",\n                    task.schema_version,\n                    CURRENT_TASK_SCHEMA_VERSION\n                );\n            }\n            ensure_safe_storage_id(\"task id\", &task.id)?;\n            if path.file_stem().and_then(|stem| stem.to_str()) != Some(task.id.as_str()) {\n                bail!(\"Task record identity differs from its path\");\n            }\n            if let Some(scope) = &task.execution_scope {\n                validate_execution_id(scope, 64)?;\n            }\n            if let Some(generation) = &task.execution_generation {\n                validate_execution_id(generation, 32)?;\n                if task.execution_scope.is_none() {\n                    bail!(\"Task generation has no execution scope\");\n                }\n            }\n            tasks.insert(task.id.clone(), task);\n        }\n    }\n\n    let mut queue = if queue_path.exists() {\n        let content = fs::read_to_string(queue_path)\n            .with_context(|| format!(\"Failed to read queue file {}\", queue_path.display()))?;\n        let parsed: QueueFile = serde_json::from_str(&content)","sourceCodeStart":3152,"sourceCodeEnd":3188,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/task_manager.rs#L3152-L3188","documentation":"Each task file must be named <task_id>.json, and the record inside must carry that same id. After validating the id is a safe storage id, the manager compares the file stem to task.id; a mismatch means the durable identity and the record disagree, which would corrupt id-based lookups, so it fails.","triggerScenarios":"Loading a task file whose filename stem (e.g. other_id from other_id.json) does not equal the decoded record's `task.id` — typically after a manual rename, copy, or hand-edited record.","commonSituations":"Manually renaming a .json task file; copying a task file to seed a new task without editing the inner id; a restore/sync tool that renamed files but not contents; a merge of two stores.","solutions":["Rename the file so its stem equals the record's `task.id` (or vice versa: edit record.id to match the filename)","Regenerate the task properly instead of copying files manually","Re-run recovery after fixing, and avoid hand-editing task store files"],"exampleFix":"// before: file 9f2e....json contains id task_00ff...\ncp task_aaaa000000000000.json task_bbbb000000000000.json\n// after: also update the inner id\nsed -i 's/task_aaaa000000000000/task_bbbb000000000000/' task_bbbb000000000000.json","handlingStrategy":"validation","validationCode":"let stem = path.file_stem().and_then(|s| s.to_str()).unwrap_or_default();\nif stem != record.id { return Err(anyhow!(\"filename {stem} does not match record id {}\", record.id)); }","typeGuard":"fn file_matches_record(path: &Path, record: &TaskRecord) -> bool {\n    path.file_stem().and_then(|s| s.to_str()) == Some(record.id.as_str())\n}","tryCatchPattern":"match manager.load_task_file(&path).await {\n    Err(e) if e.to_string().contains(\"identity differs from its path\") => {\n        eprintln!(\"repairing: rename file to match record id\");\n        std::fs::rename(&path, dir.join(format!(\"{}.json\", record.id)))?;\n        manager.load_task_file(&path).await?;\n    }\n    other => other?,\n}","preventionTips":["Never rename or copy task files manually; use the manager API","When seeding tasks by copy, update the inner id to the new filename","Audit stores after sync/restore operations for file/content identity mismatches"],"tags":["identity","persistence","consistency","task-manager"],"backgroundTag":"internal-invariant-violation","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}