microsoft/semantic-kernel · error · ServiceInvalidRequestError

offset must be greater than or equal to 0.

Error message

offset must be greater than or equal to 0.

What it means

A validation guard: the offset (skip) must be >= 0. Negative offsets are rejected client-side with ServiceInvalidRequestError before the request is sent. The check at brave.py:250-251 fires in _validate_options.

Source

Thrown at python/semantic_kernel/connectors/brave.py:250

                return BraveSearchResponse.model_validate_json(response.text)
        except HTTPStatusError as ex:
            logger.error(f"Failed to get search results: {ex}")
            raise ServiceInvalidRequestError("Failed to get search results.") from ex
        except RequestError as ex:
            logger.error(f"Client error occurred: {ex}")
            raise ServiceInvalidRequestError("A client error occurred while getting search results.") from ex
        except Exception as ex:
            logger.error(f"An unexpected error occurred: {ex}")
            raise ServiceInvalidRequestError("An unexpected error occurred while getting search results.") from ex

    def _validate_options(self, options: SearchOptions) -> None:
        if options.top <= 0:
            raise ServiceInvalidRequestError("count value must be greater than 0.")
        if options.top >= 21:
            raise ServiceInvalidRequestError("count value must be less than 21.")

        if options.skip < 0:
            raise ServiceInvalidRequestError("offset must be greater than or equal to 0.")
        if options.skip > 9:
            raise ServiceInvalidRequestError("offset must be less than 10.")

    def _get_url(self) -> str:
        return DEFAULT_URL

    def _parse_filter_lambda(self, filter_lambda: Callable | str) -> list[dict[str, str]]:
        """Parse a string lambda or string expression into a list of {field: value} dicts using AST."""
        expr = filter_lambda if isinstance(filter_lambda, str) else getsource(filter_lambda).strip()
        tree = ast.parse(expr, mode="eval")
        node = tree.body
        visitor = SearchLambdaVisitor(valid_parameters=QUERY_PARAMETERS)
        visitor.visit(node)
        return visitor.filters

    def _build_request_parameters(self, query: str, options: SearchOptions) -> dict[str, str | int | bool]:
        params: dict[str, str | int] = {"q": query or "", "count": options.top, "offset": options.skip}
        if not options.filter:

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Clamp skip to >= 0 before calling search (max(0, computed_offset)).
  2. Guard pagination state so offset never goes negative.
  3. Pass skip=0 explicitly for the first page.

Example fix

// before
results = await connector.search(query, skip=-5)
// after
results = await connector.search(query, skip=max(0, computed_offset))
Defensive patterns

Strategy: validation

Validate before calling

if skip < 0:
    raise ValueError("skip must be >= 0")
results = await connector.search(query, skip=max(0, skip))

Type guard

def is_valid_skip(skip: int) -> bool:
    return isinstance(skip, int) and 0 <= skip <= 9

Prevention

When it happens

Trigger: Calling search() with skip < 0, e.g. from a pagination state that decremented below zero.

Common situations: A 'previous page' action that subtracts page size without clamping at zero, or an off-by-one in offset computation.

Related errors


AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13). Data as JSON: /api/errors/359e8a688f3c6d34. Report an issue: GitHub.