{"record":{"id":"722602b11e6e918d","repo":"can1357/oh-my-pi","slug":"computed-edit-range-is-out-of-bounds","errorCode":null,"errorMessage":"Computed edit range is out of bounds","messagePattern":"Computed edit range is out of bounds","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"critical","filePath":"crates/pi-ast/src/ops.rs","lineNumber":328,"sourceCode":"\t\t\t&& a.deleted_length == b.deleted_length\n\t\t\t&& a.inserted_text == b.inserted_text\n\t});\n\tlet mut prev_end = 0usize;\n\tfor edit in &sorted {\n\t\tif edit.position < prev_end {\n\t\t\treturn Err(anyhow!(\n\t\t\t\t\"Overlapping replacements detected; refine pattern to avoid ambiguous edits\"\n\t\t\t));\n\t\t}\n\t\tprev_end = edit.position.saturating_add(edit.deleted_length);\n\t}\n\n\tlet mut output = content.to_string();\n\tfor edit in sorted.into_iter().rev() {\n\t\tlet start = edit.position;\n\t\tlet end = edit.position.saturating_add(edit.deleted_length);\n\t\tif end > output.len() || start > end {\n\t\t\treturn Err(anyhow!(\"Computed edit range is out of bounds\"));\n\t\t}\n\t\tlet replacement = std::str::from_utf8(&edit.inserted_text)\n\t\t\t.map_err(|err| anyhow!(\"Replacement text is not valid UTF-8: {err}\"))?;\n\t\toutput.replace_range(start..end, replacement);\n\t}\n\tOk(output)\n}\n\npub fn collect_matched_files(\n\tcwd: &Path,\n\tpatterns: &[String],\n) -> Result<Vec<MatchedFile>, std::io::Error> {\n\tlet globset = build_globset(patterns)?;\n\tlet mut builder = WalkBuilder::new(cwd);\n\tbuilder\n\t\t.hidden(false)\n\t\t.git_ignore(true)\n\t\t.git_global(true)","sourceCodeStart":310,"sourceCodeEnd":346,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/crates/pi-ast/src/ops.rs#L310-L346","documentation":"Writing the JSON command frame to the subprocess stdin raised BrokenPipeError or OSError. The client converts it to RpcProcessExitError with the underlying OS message, since a failed stdin write almost always means the child process has exited.","triggerScenarios":"Child RPC process died before/during the write; pipe buffer closed concurrently by stop(); EPIPE/EIO from the OS when the read end of the pipe is closed.","commonSituations":"Server crash from an unhandled exception, out-of-memory kill, or the server exiting after an earlier protocol error — the next request write then fails with a broken pipe.","solutions":["Restart the RPC client (stop, new instance, start) and retry; the old process cannot be written to.","Inspect server stderr and exit code to diagnose the original crash.","Serialize stop() and request calls (locks/async ordering) so stop() doesn't close stdin mid-write.","Wrap all requests in try/except RpcProcessExitError with automatic restart logic."],"exampleFix":"// before\nawait client.stop()\nawait client.request(\"prompt\", {...})  # broken pipe: stdin already closed\n// after\nawait client.stop()\nawait client.start()\nawait client.request(\"prompt\", {...})","handlingStrategy":"try-catch","validationCode":"proc = client._process\nif proc is None or proc.poll() is not None:\n    raise RuntimeError(\"RPC server not running; restart before sending commands\")","typeGuard":"def can_write(client: RpcClient) -> bool:\n    p = client._process\n    return p is not None and p.stdin is not None and p.poll() is None","tryCatchPattern":"try:\n    result = await client.request(\"prompt\", payload)\nexcept RpcProcessExitError as exc:\n    logger.error(\"RPC write failed, restarting client\", exc_info=exc)\n    await client.stop()\n    await client.start()\n    result = await client.request(\"prompt\", payload)","preventionTips":["Add automatic restart-and-retry (with backoff) around all RPC requests.","Never call stop() concurrently with in-flight requests; await pending requests first.","Persist server stderr to logs so broken-pipe crashes are diagnosable."],"tags":["process","rpc","broken-pipe","io"],"backgroundTag":"broken-pipe","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}