{"record":{"id":"53df927a45e98afe","repo":"affaan-m/ECC","slug":"remote-dispatch-request-id-was-not-found-after-i","errorCode":null,"errorMessage":"Remote dispatch request {id} was not found after insert","messagePattern":"Remote dispatch request (.+?) was not found after insert","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"ecc2/src/session/store.rs","lineNumber":1670,"sourceCode":"                target_session_id,\n                task,\n                target_url,\n                task_priority_db_value(priority),\n                agent_type,\n                profile_name,\n                working_dir.display().to_string(),\n                project,\n                task_group,\n                if use_worktree { 1_i64 } else { 0_i64 },\n                source,\n                requester,\n                now.to_rfc3339(),\n                now.to_rfc3339(),\n            ],\n        )?;\n        let id = self.conn.last_insert_rowid();\n        self.get_remote_dispatch_request(id)?.ok_or_else(|| {\n            anyhow::anyhow!(\"Remote dispatch request {id} was not found after insert\")\n        })\n    }\n\n    pub fn list_remote_dispatch_requests(\n        &self,\n        include_processed: bool,\n        limit: usize,\n    ) -> Result<Vec<RemoteDispatchRequest>> {\n        let sql = if include_processed {\n            \"SELECT id, request_kind, target_session_id, task, target_url, priority, agent_type, profile_name, working_dir,\n                    project, task_group, use_worktree, source, requester, status,\n                    result_session_id, result_action, error, created_at, updated_at, dispatched_at\n             FROM remote_dispatch_requests\n             ORDER BY CASE status WHEN 'pending' THEN 0 WHEN 'failed' THEN 1 ELSE 2 END ASC,\n                      priority DESC, created_at ASC, id ASC\n             LIMIT ?1\"\n        } else {\n            \"SELECT id, request_kind, target_session_id, task, target_url, priority, agent_type, profile_name, working_dir,","sourceCodeStart":1652,"sourceCodeEnd":1688,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/ecc2/src/session/store.rs#L1652-L1688","documentation":"Raised by the remote-dispatch-request insertion helper in ecc2/src/session/store.rs:1670 when get_remote_dispatch_request(id) returns None right after INSERT INTO ... and last_insert_rowid. Same class as the scheduled-task read-back failure: the row is not visible to the inserting connection, typically due to triggers, a shared connection, or the table being a view.","triggerScenarios":"A trigger or INSTEAD OF rule on the dispatch-requests table swallows the insert; last_insert_rowid returns an id from a different table because a concurrent insert on the same shared connection landed between the INSERT and the read of last_insert_rowid; the table was converted to a view by a migration.","commonSituations":"Cross-thread use of a single rusqlite Connection without the actor mutex; a custom migration added an AFTER INSERT trigger that moves rows; schema drift after a partial upgrade.","solutions":["Check SELECT sql FROM sqlite_master WHERE type='trigger' AND tbl_name LIKE '%dispatch%' for intercepting triggers.","Wrap insert + read-back in a transaction and read back within the same tx so no other write can interfere.","Guarantee the connection is used by one logical writer at a time (the DbWriter actor pattern); last_insert_rowid is only meaningful before any other write on that connection.","SELECT by rowid in get_remote_dispatch_request to rule out id-derivation bugs."],"exampleFix":"// before\nself.conn.execute(\"INSERT INTO ... dispatch ...\", params![...])?;\nlet id = self.conn.last_insert_rowid();\nself.get_remote_dispatch_request(id)?.ok_or_else(|| anyhow!(\"not found after insert\"))\n\n// after: atomic insert + read-back in one tx\nlet tx = self.conn.transaction()?;\ntx.execute(\"INSERT INTO ... dispatch ...\", params![...])?;\nlet id = tx.last_insert_rowid();\nlet req = get_remote_dispatch_request_in_tx(&tx, id)?.ok_or_else(|| anyhow!(\"not found after insert\"))?;\ntx.commit()?;\nOk(req)","handlingStrategy":"validation","validationCode":"// Same transactional defense as errorIndex 710, applied to dispatch requests.\npub fn create_remote_dispatch_request_atomic(&self, /* fields */) -> anyhow::Result<RemoteDispatchRequest> {\n    let tx = self.conn.transaction()?;\n    tx.execute(\n        \"INSERT INTO remote_dispatch_requests (...) VALUES (...)\",\n        rusqlite::params![...],\n    )?;\n    let id = tx.last_insert_rowid();\n    let req = get_remote_dispatch_request_in_tx(&tx, id)?\n        .ok_or_else(|| anyhow::anyhow!(\"dispatch request {id} not found after insert\"))?;\n    tx.commit()?;\n    Ok(req)\n}\n\nfn assert_no_dispatch_triggers(conn: &rusqlite::Connection) -> anyhow::Result<()> {\n    let n: i64 = conn.query_row(\n        \"SELECT COUNT(*) FROM sqlite_master WHERE type='trigger' AND tbl_name LIKE '%dispatch%'\",\n        [], |r| r.get(0),\n    )?;\n    if n > 0 { anyhow::bail!(\"{n} triggers on dispatch tables may intercept inserts\"); }\n    Ok(())\n}","typeGuard":"// No type guard; the issue is connection/transaction usage. The defense is\n// the transaction wrapper and the trigger audit above.","tryCatchPattern":"match store.create_remote_dispatch_request(/* ... */) {\n    Ok(req) => Ok(req),\n    Err(e) if e.to_string().contains(\"not found after insert\") => {\n        tracing::error!(\"dispatch insert/read-back mismatch; check triggers and shared connections\");\n        Err(e)\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Wrap insert + read-back in a transaction; read back inside the tx.","Keep the Connection single-writer; last_insert_rowid is only valid before any other write on that connection.","Audit sqlite_master for triggers/views on the dispatch tables after migrations.","Do not share a Connection across threads without serialization."],"tags":["database","sqlite","remote-dispatch","insert","last-insert-rowid","transaction"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}