{"record":{"id":"5586a6720d9172ff","repo":"Hmbown/CodeWhale","slug":"fork-at-user-message-depth-exceeds-user-tur","errorCode":null,"errorMessage":"fork_at_user_message: depth {} exceeds {} user turn(s)","messagePattern":"fork_at_user_message: depth (.+?) exceeds (.+?) user turn\\(s\\)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/runtime_threads.rs","lineNumber":5051,"sourceCode":"        depth_from_tail: usize,\n    ) -> Result<(ThreadRecord, Option<String>)> {\n        let source = self.get_thread(id).await?;\n        let source_turns = self.store.list_turns_for_thread(&source.id)?;\n\n        // Walk turns from newest to oldest. For each turn, ask: does it\n        // contain a UserMessage item? If yes, it counts toward the depth.\n        let mut user_turn_indices: Vec<usize> = Vec::new();\n        for (idx, turn) in source_turns.iter().enumerate().rev() {\n            let items = self.store.list_items_for_turn(&turn.id)?;\n            if items\n                .iter()\n                .any(|item| item.kind == TurnItemKind::UserMessage)\n            {\n                user_turn_indices.push(idx);\n            }\n        }\n        if depth_from_tail >= user_turn_indices.len() {\n            bail!(\n                \"fork_at_user_message: depth {} exceeds {} user turn(s)\",\n                depth_from_tail,\n                user_turn_indices.len()\n            );\n        }\n        // `user_turn_indices` is newest-first because we iterated in\n        // reverse, so the Nth element is exactly the Nth-from-tail user\n        // turn in the original chronological list.\n        let target_turn_idx = user_turn_indices[depth_from_tail];\n        let target_turn_id = source_turns[target_turn_idx].id.clone();\n\n        // Pull the original user-message text out of the dropped turn so\n        // the caller can drop it back into the composer.\n        let target_items = self.store.list_items_for_turn(&target_turn_id)?;\n        let original_user_text = target_items\n            .iter()\n            .find(|item| item.kind == TurnItemKind::UserMessage)\n            .and_then(|item| item.detail.clone());","sourceCodeStart":5033,"sourceCodeEnd":5069,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/runtime_threads.rs#L5033-L5069","documentation":"fork_at_user_message counted user messages walking the thread's turns from newest to oldest and the requested depth exceeds how many exist. Depth is tail-relative (1 = most recent user message), so this means the caller asked to fork at a user turn further back than the thread contains.","triggerScenarios":"Thrown at crates/tui/src/runtime_threads.rs:5051 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Count the user turns in the thread","Request a depth within that count"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}