{"record":{"id":"0e3f914d8baeae16","repo":"can1357/oh-my-pi","slug":"offset-start-line-is-beyond-end-of-output-to","errorCode":null,"errorMessage":"Offset #{start_line} is beyond end of output (#{total_lines} lines) for #{output_id}","messagePattern":"Offset #(.+?) is beyond end of output \\(#(.+?) lines\\) for #(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/eval/rb/prelude.rb","lineNumber":221,"sourceCode":"        json_value =\n          begin\n            JSON.parse(raw)\n          rescue JSON::ParserError => e\n            __omp_emit_status(\"output\", \"id\" => output_id, \"error\" => \"Not valid JSON: #{e.message}\")\n            raise \"Output #{output_id} is not valid JSON: #{e.message}\"\n          end\n        result_value = __omp_apply_query(json_value, query)\n        selected =\n          begin\n            result_value.nil? ? \"null\" : JSON.pretty_generate(result_value)\n          rescue StandardError\n            result_value.to_s\n          end\n      elsif !offset.nil? || !limit.nil?\n        start_line = [offset || 1, 1].max\n        if start_line > total_lines\n          __omp_emit_status(\"output\", \"id\" => output_id, \"error\" => \"Offset #{start_line} beyond end (#{total_lines} lines)\")\n          raise \"Offset #{start_line} is beyond end of output (#{total_lines} lines) for #{output_id}\"\n        end\n        effective_limit = limit || (total_lines - start_line + 1)\n        end_line = [total_lines, start_line + effective_limit - 1].min\n        selected = raw_lines[(start_line - 1)...end_line].join(\"\\n\")\n        range_info = { \"start_line\" => start_line, \"end_line\" => end_line, \"total_lines\" => total_lines }\n      end\n\n      selected = selected.gsub(/\\e\\[[0-9;]*m/, \"\") if format == \"stripped\"\n\n      if format == \"json\"\n        entry = {\n          \"id\" => output_id,\n          \"path\" => path,\n          \"line_count\" => query ? selected.split(\"\\n\").length : total_lines,\n          \"char_count\" => query ? selected.length : raw.length,\n          \"content\" => selected,\n        }\n        entry[\"range\"] = range_info if range_info","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/eval/rb/prelude.rb#L203-L239","documentation":"When `output` is called with `offset` (and/or `limit`), the artifact is paged by lines. The offset is clamped to a minimum of 1, but if the requested start line exceeds the artifact's total line count there is nothing to return, so the prelude raises with the requested start line, the total lines, and the output ID.","triggerScenarios":"Calling `output('<id>', offset: N)` (or `offset: N, limit: M`) where the `<id>.md` artifact has fewer than N lines — e.g. a 3-line log fetched with `offset: 10`, or a stale cached line count reused after the artifact was regenerated shorter.","commonSituations":"Paging through an artifact with a fixed page size and running past the end; re-running a paging script after the artifact shrank; off-by-one assumptions that offset is zero-based (clamped to 1 here).","solutions":["Use a smaller offset within the artifact's actual length (the error message states total_lines).","Detect the end of paging: catch the error and stop paginating, or first read without offset and count lines.","If you need to know the size up front, fetch `format: 'json'` and use the returned `line_count` before computing the next offset."],"exampleFix":"// before\nchunk = output('log', offset: 500, limit: 100)  # file only has 120 lines\n// after\ninfo = output('log', format: 'json')\nchunk = info['line_count'] >= 500 ? output('log', offset: 500, limit: 100) : nil","handlingStrategy":"validation","validationCode":"info = output(id, format: 'json')\ntotal = info['line_count']\nraise RangeError, 'offset past end' if offset > total","typeGuard":null,"tryCatchPattern":"begin\n  chunk = output(id, offset: next_offset, limit: page_size)\nrescue RuntimeError => e\n  raise unless e.message =~ /beyond end of output/\n  chunk = nil # reached end of artifact\nend","preventionTips":["Stop paginating when a returned page is shorter than the requested limit instead of issuing one more page.","Fetch line_count via format: 'json' before computing offsets.","Clamp offset to [1, total_lines] before calling."],"tags":["ruby","range-error","eval-prelude","pagination"],"backgroundTag":"offset-out-of-range","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}