{"record":{"id":"022a4cd1a9dc69fc","repo":"sinelaw/fresh","slug":"failed-to-read-data-at-offset-no-progress-made-requested","errorCode":null,"errorMessage":"Failed to read data at offset {}: no progress made (requested {}..{}, buffer len: {})","messagePattern":"Failed to read data at offset (.+?): no progress made \\(requested (.+?)\\.\\.(.+?), buffer len: (.+?)\\)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/fresh-editor-core/src/model/buffer/mod.rs","lineNumber":1438,"sourceCode":"                    current_offset = read_end;\n                    made_progress = true;\n                }\n            }\n\n            // If we didn't make progress and didn't restart iteration, this is an error\n            if !made_progress && !restarted_iteration {\n                tracing::error!(\n                    \"get_text_range_mut: No progress at offset {} (requested range: {}..{}, buffer len: {})\",\n                    current_offset,\n                    offset,\n                    end_offset,\n                    self.len()\n                );\n                tracing::error!(\n                    \"Piece tree stats: {} total bytes\",\n                    self.piece_tree.stats().total_bytes\n                );\n                anyhow::bail!(\n                    \"Failed to read data at offset {}: no progress made (requested {}..{}, buffer len: {})\",\n                    current_offset,\n                    offset,\n                    end_offset,\n                    self.len()\n                );\n            }\n        }\n\n        if iteration_count > 1 {\n            tracing::info!(\n                iteration_count,\n                result_len = result.len(),\n                \"get_text_range_mut: completed with multiple iterations\"\n            );\n        }\n\n        crate::counters::work::add_buffer_bytes_read(result.len() as u64);","sourceCodeStart":1420,"sourceCodeEnd":1456,"githubUrl":"https://github.com/sinelaw/fresh/blob/67894ca5463dbd7a89bb31add4627c27d6b79d83/crates/fresh-editor-core/src/model/buffer/mod.rs#L1420-L1456","documentation":"The piece-tree buffer's read path walks chunks to satisfy a byte-range read. If an iteration over the piece tree makes no forward progress (current_offset doesn't advance toward end_offset), an internal invariant has been broken — continuing would loop forever — so the code logs piece-tree stats and bails with 'Failed to read data at offset ...: no progress made'. This indicates a corrupted piece tree or a bug, not bad user input.","triggerScenarios":"Requesting read_data (or a bulk read spanning ranges) at an offset/end range when the chunk walk fails to advance current_offset — typically a piece-tree invariant violation: stale piece references after edits, an offset beyond current length slipping past earlier checks, or a deletion/undo that left empty/zero-length pieces in the walk.","commonSituations":"After complex undo/redo or concurrent edit sequences that corrupt piece ordering; extension/API code caching offsets and reading after the buffer shrank; genuinely a library bug — users rarely trigger it intentionally.","solutions":["Report/inspect as a bug: capture the logged piece-tree stats (len, total_bytes) and the offset range from the message.","Reload the buffer from disk (re-open the file) to rebuild a clean piece tree.","Verify callers pass offsets derived from the buffer's current len() and refresh cached offsets after edits.","If reproducible, reduce to a minimal edit/undo sequence and file an issue with the reproduction steps."],"exampleFix":"// before: stale offset cached before a deletion\nlet off = buffer.len();\nbuffer.delete(...);\nbuffer.read_data(off..off + n)?; // no-progress bail\n\n// after: clamp to the current length at read time\nlet off = off.min(buffer.len());\nlet end = (off + n).min(buffer.len());\nbuffer.read_data(off..end)?;","handlingStrategy":"validation","validationCode":"// Rust: clamp read ranges to the buffer's current length\nlet off = offset.min(buffer.len());\nlet end = end_offset.min(buffer.len());\nif off >= end { return Ok(Vec::new()); }","typeGuard":null,"tryCatchPattern":"match buffer.read_data(range) {\n    Err(e) if e.to_string().contains(\"no progress made\") => {\n        tracing::error!(\"piece tree invariant violation: {e}\");\n        // recover by reloading the buffer from disk\n        buffer = Buffer::load_file(path)?;\n    }\n    other => other?,\n}","preventionTips":["Never cache byte offsets across edits; re-read len() before each range read.","Treat this error as a bug report trigger — capture the logged piece-tree stats.","Reload the buffer from disk after encountering it; the piece tree may be corrupted."],"tags":["piece-tree","invariant","buffer","read","internal-error"],"backgroundTag":"internal-invariant-violation","analyzedSha":"67894ca5463dbd7a89bb31add4627c27d6b79d83","analyzedAt":"2026-09-13T15:04:03.701Z","contentChangedAt":"2026-09-13T15:04:03.701Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}