{"record":{"id":"4452eb9da741ac00","repo":"Hmbown/CodeWhale","slug":"invalid-preallocated-task-id-expected-task-16hex","errorCode":null,"errorMessage":"Invalid preallocated task id: expected task_<16hex>","messagePattern":"Invalid preallocated task id: expected task_<16hex>","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/task_manager.rs","lineNumber":1237,"sourceCode":"        format!(\"task_{}\", &Uuid::new_v4().simple().to_string()[..16])\n    }\n\n    /// Enqueue using a preallocated id. This is crate-visible only for the\n    /// model tool's register-before-work transaction.\n    pub(crate) async fn add_task_with_id(\n        &self,\n        req: NewTaskRequest,\n        task_id: String,\n    ) -> Result<TaskRecord> {\n        let prompt = req.prompt.trim().to_string();\n        if prompt.is_empty() {\n            bail!(\"Task prompt cannot be empty\");\n        }\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\n        let task = TaskRecord {\n            schema_version: CURRENT_TASK_SCHEMA_VERSION,\n            // 16 random hex chars (was 8; ~60 bits of entropy once UUIDv4's\n            // fixed version nibble is discounted): task ids live in durable\n            // state that accumulates across restarts, and a collision\n            // overwrites a record while leaving a duplicate queue entry.\n            // `resolve_task_id` matches by prefix, so short references still\n            // work.\n            id: task_id,\n            prompt,\n            model: req.model.unwrap_or_else(|| self.cfg.default_model.clone()),\n            workspace: match req.workspace {\n                Some(workspace) => workspace,\n                None => self.default_workspace().await,\n            },\n            mode: req.mode.unwrap_or_else(|| self.cfg.default_mode.clone()),","sourceCodeStart":1219,"sourceCodeEnd":1255,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/task_manager.rs#L1219-L1255","documentation":"add_task_with_id validates the caller-supplied preallocated id: it must be exactly 21 chars, start with 'task_', and the remaining 16 characters must be ASCII hex digits. The 16-hex format (about 60 bits of entropy) replaced an older 8-hex format because task records accumulate across restarts and a collision would overwrite a record while leaving a duplicate queue entry.","triggerScenarios":"Passing an id generated by old code that produced task_ + 8 hex chars; passing a UUID, an arbitrary string, uppercase hex, or a wrong-length id to add_task_with_id.","commonSituations":"Upgrading a codebase that generated task_<8hex> ids before this format change; mixing hand-written id generators with the task manager; copy-pasting ids from logs that were truncated.","solutions":["Generate ids exactly the way the task manager does: format!(\"task_{}\", &Uuid::new_v4().simple().to_string()[..16]).","If you hold a persistent id generator, enforce len==21, prefix 'task_', and [0-9a-f] over the last 16 chars before calling.","Regenerate rather than repair malformed ids at runtime; never widen the parser to accept the legacy 8-hex form."],"exampleFix":"// before\nlet id = format!(\"task_{:08x\", rand::random::<u32>()); // 8 hex, wrong length\nlet task = tm.add_task_with_id(req, id).await?;\n\n// after\nlet id = format!(\"task_{}\", &Uuid::new_v4().simple().to_string()[..16]);\nlet task = tm.add_task_with_id(req, id).await?;","handlingStrategy":"validation","validationCode":"fn is_valid_task_id(id: &str) -> bool {\n    id.len() == 21\n        && id.starts_with(\"task_\")\n        && id[5..].chars().all(|ch| ch.is_ascii_hexdigit())\n}\n\nfn new_task_id() -> String {\n    format!(\"task_{}\", &Uuid::new_v4().simple().to_string()[..16])\n}","typeGuard":"fn is_task_id(id: &str) -> bool {\n    id.len() == 21 && id.starts_with(\"task_\") && id[5..].bytes().all(|b| b.is_ascii_hexdigit())\n}","tryCatchPattern":null,"preventionTips":["Always mint ids with the same generator as the task manager (task_ + 16 lowercase hex).","Never persist externally-generated free-form ids; validate them at the boundary.","Watch for the legacy 8-hex format after upgrades and regenerate instead of padding."],"tags":["task","validation","identifier","rust"],"backgroundTag":"invalid-identifier-format","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}