{"record":{"id":"f63a67d900b57fa8","repo":"Hmbown/CodeWhale","slug":"bound-task-identity-or-schema-does-not-match-its-durable","errorCode":null,"errorMessage":"Bound task identity or schema does not match its durable admission","messagePattern":"Bound task identity or schema does not match its durable admission","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/task_manager.rs","lineNumber":3097,"sourceCode":"fn validate_preallocated_task_id(task_id: &str) -> Result<()> {\n    if task_id.len() != 21\n        || !task_id.starts_with(\"task_\")\n        || !task_id[5..].chars().all(|ch| ch.is_ascii_hexdigit())\n    {\n        bail!(\"Invalid preallocated task id: expected task_<16hex>\");\n    }\n    Ok(())\n}\n\nfn read_bound_task_file(path: &Path, task_id: &str) -> Result<Option<TaskRecord>> {\n    let bytes = match fs::read(path) {\n        Ok(bytes) => bytes,\n        Err(error) if error.kind() == std::io::ErrorKind::NotFound => return Ok(None),\n        Err(error) => return Err(error).context(\"read bound task\"),\n    };\n    let task: TaskRecord = serde_json::from_slice(&bytes).context(\"decode bound task\")?;\n    if task.id != task_id || task.schema_version > CURRENT_TASK_SCHEMA_VERSION {\n        bail!(\"Bound task identity or schema does not match its durable admission\");\n    }\n    Ok(Some(task))\n}\n\npub(crate) fn validate_bound_task_request(\n    task: &TaskRecord,\n    request: &NewTaskRequest,\n) -> Result<()> {\n    if task.prompt != request.prompt.trim()\n        || task.owner_session_id != request.owner_session_id\n        || task.model_provider != request.model_provider\n        || task.model_provider_id != request.model_provider_id\n        || request\n            .model\n            .as_ref()\n            .is_some_and(|value| value != &task.model)\n        || request\n            .workspace","sourceCodeStart":3079,"sourceCodeEnd":3115,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/task_manager.rs#L3079-L3115","documentation":"When reading a durable bound-task file, the decoded TaskRecord must have the same id as the file's bound task id and a schema_version not newer than the current supported version. Otherwise the durable admission cannot be matched to the request, so the read fails rather than trusting a mismatched record.","triggerScenarios":"Calling read_bound_task_file (directly or via recovery/admission) when the JSON record's `id` differs from the requested task_id, or its schema_version exceeds CURRENT_TASK_SCHEMA_VERSION.","commonSituations":"A task file was renamed or copied under the wrong id; a newer app version wrote the file and an older version reads it (forward-compatibility gap); a client passed a task_id that doesn't match the stored record.","solutions":["Upgrade to the newer app version whose CURRENT_TASK_SCHEMA_VERSION covers the file","Correct the task_id argument to match the record actually stored in the file","Fix or remove the mis-named task file so identity matches its durable location"],"exampleFix":"// before: reading with mismatched id\nlet t = manager.read_bound_task(\"task_0000000000000000\")?;\n// after: match id to file content\nlet t = manager.read_bound_task(&stored_task_id)?; // stored_task_id == record.id","handlingStrategy":"validation","validationCode":"let record: TaskRecord = serde_json::from_slice(&bytes)?;\nif record.id != requested_id { return Err(anyhow!(\"id mismatch with durable file\")); }\nif record.schema_version > CURRENT_TASK_SCHEMA_VERSION { return Err(anyhow!(\"schema too new\")); }","typeGuard":"fn bound_record_matches(bytes: &[u8], task_id: &str, supported: u32) -> Option<TaskRecord> {\n    let t: TaskRecord = serde_json::from_slice(bytes).ok()?;\n    (t.id == task_id && t.schema_version <= supported).then_some(t)\n}","tryCatchPattern":"match manager.read_bound_task(id).await {\n    Err(e) if e.to_string().contains(\"identity or schema does not match\") => {\n        // try newer app version, or locate the correctly named file\n        eprintln!(\"bound record unusable for {id}: {e}\");\n    }\n    other => other?,\n}","preventionTips":["Never rename task files without updating the inner id","Keep app versions across a shared store within the same schema version","Check schema_version support before reading a store written elsewhere"],"tags":["validation","schema-version","identity","task-manager"],"backgroundTag":"schema-validation-failed","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}