{"record":{"id":"8dff8ecc7d46e411","repo":"zeroclaw-labs/zeroclaw","slug":"goal-task-task-id-has-no-canonical-taskkind-goa","errorCode":null,"errorMessage":"goal task {task_id} has no canonical TaskKind::Goal row and goal extension","messagePattern":"goal task (.+?) has no canonical TaskKind::Goal row and goal extension","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-runtime/src/control_plane/task_store_sqlite/goal.rs","lineNumber":340,"sourceCode":"}\n\nfn ensure_goal_task_row(conn: &Connection, task_id: &str) -> Result<()> {\n    let exists = conn\n        .query_row(\n            \"SELECT EXISTS(\n                 SELECT 1\n                   FROM tasks\n                   JOIN goal_tasks ON goal_tasks.task_id = tasks.id\n                  WHERE tasks.id = ?1\n                    AND tasks.kind = 'goal'\n             )\",\n            params![task_id],\n            |row| row.get::<_, i64>(0),\n        )\n        .context(\"verify goal task row\")?\n        != 0;\n    if !exists {\n        anyhow::bail!(\"goal task {task_id} has no canonical TaskKind::Goal row and goal extension\");\n    }\n    Ok(())\n}\n\nfn upsert_continuation_context(\n    conn: &Connection,\n    task_id: &str,\n    context: &TaskContinuationContext,\n) -> Result<()> {\n    conn.execute(\n        \"INSERT INTO task_continuation_contexts (task_id, context_json)\n         VALUES (?1, ?2)\n         ON CONFLICT(task_id) DO UPDATE\n             SET context_json = excluded.context_json\",\n        params![task_id, continuation_context_to_db(context)?],\n    )\n    .context(\"upsert task continuation context\")?;\n    Ok(())","sourceCodeStart":322,"sourceCodeEnd":358,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-runtime/src/control_plane/task_store_sqlite/goal.rs#L322-L358","documentation":"ensure_goal_task_row is the fail-fast guard at the start of goal lifecycle transactions (pause_goal_task, resume_goal_task, set/get_continuation_context). It verifies the canonical TaskKind::Goal row AND its goal extension row exist; if either is missing the operation is refused before any status mutation, so no partial state is written.","triggerScenarios":"Calling a goal lifecycle method with a task id that is not a goal task (wrong id, regular task, cross-environment paste) or whose goal extension row is missing (partial insert, manual DB edit, schema drift after migration).","commonSituations":"Task ids copied between environments; databases migrated or hand-edited; goals created through a path that skipped the extension insert; races with concurrent deletion.","solutions":["Verify the id exists and is TaskKind::Goal via the task list/get API before calling lifecycle methods","If the extension row is missing, recreate the goal through the proper creation API rather than hand-INSERTing","Check for concurrent deletion of the task","Add a pre-flight check in operator tooling that lists goals and their extension status"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// pre-flight before lifecycle calls\nif !matches!(store.get_task(id).await, Ok(Some(ref t)) if t.kind == TaskKind::Goal) {\n    anyhow::bail!(\"{id} is not a goal task; nothing to pause/resume\");\n}\nstore.pause_goal_task(id, pause).await?;","typeGuard":"async fn is_goal_task(store: &SqliteTaskStore, id: &str) -> bool {\n    matches!(store.get_task(id).await, Ok(Some(t)) if t.kind == TaskKind::Goal)\n}","tryCatchPattern":"match store.pause_goal_task(id, pause).await {\n    Err(ref e) if e.to_string().contains(\"has no canonical TaskKind::Goal row\") => {\n        // wrong id or structurally incomplete goal: verify and recreate via the creation API\n    }\n    other => other,\n}","preventionTips":["Select goal ids from the listing API, never hand-type them","Create goals only through the creation API so canonical + extension rows are written atomically","Never hand-edit the SQLite store","Fail lifecycle tooling fast on unknown ids"],"tags":["goal-store","task-not-found","fail-fast","sqlite","lifecycle"],"backgroundTag":"entity-not-found","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}