{"record":{"id":"d712e5d1f75da7be","repo":"langchain-ai/deepagents","slug":"readresult-window-must-satisfy-1-start-line","errorCode":null,"errorMessage":"ReadResult window must satisfy 1 <= start_line <= end_line, got start_line={self.start_line}, end_line={self.end_line}","messagePattern":"ReadResult window must satisfy 1 <= start_line <= end_line, got start_line=(.+?), end_line=(.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/deepagents/deepagents/backends/protocol.py","lineNumber":268,"sourceCode":"            raise ValueError(msg)\n        if self.no_lines_requested and (\n            self.error is not None or self.start_line is not None or self.next_offset is not None or self.total_lines is not None\n        ):\n            msg = \"ReadResult.no_lines_requested describes an uninspected window; it cannot be combined with error or pagination fields\"\n            raise ValueError(msg)\n        if self.next_offset is not None and self.start_line is None:\n            msg = \"ReadResult.next_offset requires start_line and end_line to be set\"\n            raise ValueError(msg)\n        if self.total_lines is not None and self.start_line is None:\n            msg = \"ReadResult.total_lines requires start_line and end_line to be set\"\n            raise ValueError(msg)\n\n        # Numeric consistency of a present window. `start_line`/`end_line` are\n        # bound together above, so testing `start_line` covers both.\n        if self.start_line is not None and self.end_line is not None:\n            if self.start_line < 1 or self.end_line < self.start_line:\n                msg = f\"ReadResult window must satisfy 1 <= start_line <= end_line, got start_line={self.start_line}, end_line={self.end_line}\"\n                raise ValueError(msg)\n            if self.total_lines is not None and self.total_lines < self.end_line:\n                msg = f\"ReadResult.total_lines ({self.total_lines}) cannot be less than end_line ({self.end_line})\"\n                raise ValueError(msg)\n            if self.next_offset is not None and self.next_offset != self.end_line:\n                msg = f\"ReadResult.next_offset ({self.next_offset}) must equal end_line ({self.end_line}), the 0-indexed line after the last shown\"\n                raise ValueError(msg)\n\n\n@dataclass\nclass WriteResult:\n    \"\"\"Result from backend `write` operations.\n\n    Attributes:\n        error: Error message on failure, `None` on success.\n        path: Absolute path of written file, `None` on failure.\n\n    Examples:\n        >>> WriteResult(path=\"/f.txt\")","sourceCodeStart":250,"sourceCodeEnd":286,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/deepagents/deepagents/backends/protocol.py#L250-L286","documentation":"ReadResult.__post_init__ enforces that the line window satisfies 1 <= start_line <= end_line. Line numbers in ReadResult are 1-based; a backend that reports start_line < 1 or an end_line before the start produces an impossible window and is rejected with a ValueError at construction. This guards downstream consumers (middleware, line-number formatting) from negative or inverted ranges.","triggerScenarios":"Constructing ReadResult with start_line=0 (treating lines as 0-indexed), start_line=-1 (using offset directly as a 1-based line), or swapping the fields (end_line as start). E.g. ReadResult(content=t, start_line=offset, end_line=offset+limit) with offset=0.","commonSituations":"Confusing the backend `read(offset=...)` 0-based offset parameter with the 1-based start_line field; translating a 0-indexed slice range into the result fields without adding 1; custom backends and test fixtures.","solutions":["Use 1-based numbering: start_line = offset + 1, end_line = offset + number_of_lines_returned.","Assert in your backend that 1 <= start_line <= end_line before constructing ReadResult.","If the result is empty, set start_line=None and end_line=None (or a valid degenerate window) rather than 0."],"exampleFix":"// before\nreturn ReadResult(content=text, start_line=offset, end_line=offset + len(lines))\n// after\nstart = offset + 1\nreturn ReadResult(content=text, start_line=start, end_line=start + len(lines) - 1)","handlingStrategy":"validation","validationCode":"def check_window(start_line, end_line):\n    if start_line is not None and end_line is not None:\n        assert 1 <= start_line <= end_line, f'bad window {start_line}-{end_line}'","typeGuard":"def has_valid_window(r) -> bool:\n    return r.start_line is None or (1 <= r.start_line <= (r.end_line or 0) + 1 and r.end_line >= r.start_line)","tryCatchPattern":"try:\n    return ReadResult(content=text, start_line=start, end_line=end)\nexcept ValueError:\n    return ReadResult(content=text)  # degrade to unpaginated result","preventionTips":["Remember ReadResult line numbers are 1-based; convert the 0-based offset with offset + 1.","Add an assertion at the end of your backend's read before constructing the result.","Test with offset=0 specifically — it is the classic source of start_line=0 bugs."],"tags":["validation","off-by-one","backend-protocol"],"backgroundTag":"invalid-line-range","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}