zylon-ai/private-gpt · error · ValueError

Offset cannot be negative

Error message

Offset cannot be negative

What it means

ValueError from BraveSearchProvider._validate_query_params when the pagination offset is negative. Brave Search pagination uses offset >= 0; the provider validates this client-side (note that num_links out of range is only clamped with a warning, but a negative offset is a hard error).

Solutions

  1. Clamp offset at the call site: offset = max(0, desired_offset).
  2. Fix the pagination arithmetic (use page-1 with pages starting at 1, or multiply 0-based index by page size).
  3. Add a unit test asserting offsets never go negative for the first page.

Example fix

# before
offset = (page - 1) * page_size  # page is 0-based -> -page_size on first call

# after
offset = max(0, page) * page_size  # or page starting at 1
Defensive patterns

Strategy: validation

Validate before calling

def normalize_offset(offset: int) -> int:
    if offset < 0:
        raise ValueError('offset must be >= 0')
    return offset

offset = normalize_offset((page - 1) * page_size if page >= 1 else 0)

Try / catch

try:
    results = await provider.make_query(q, n, offset=offset)
except ValueError as e:
    if str(e) == 'Offset cannot be negative':
        results = await provider.make_query(q, n, offset=0)
    else:
        raise

Prevention

When it happens

Trigger: Passing offset=-1 via make_query kwargs (e.g. search(query, offset=page-1) with page=0); a pagination UI computing offset as (page-1)*n with page starting at 0 instead of 1.

Common situations: Off-by-one bugs in pagination loops; callers mixing 0-based page indices with Brave's page/offset semantics.

Related errors


AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15). Data as JSON: /api/errors/b36eb6df7031f906. Report an issue: GitHub.

Appendix: source

Thrown at private_gpt/components/web/web_search/providers/brave.py:96

    async def validate(self) -> None:
        if not self._api_key or not self._api_key.strip():
            raise ValueError("Brave Search API key is not configured")

    def _validate_query_params(
        self, query: str, num_links: int, offset: int
    ) -> tuple[str, int, int]:
        if not query or not query.strip():
            raise ValueError("Search query cannot be empty")

        normalized_num_links = max(1, min(20, num_links))  # Brave allows 1-20
        if normalized_num_links != num_links:
            logger.warning(
                f"Num_links {num_links} outside valid range [1,20], clamped to {normalized_num_links}"
            )

        if offset < 0:
            raise ValueError("Offset cannot be negative")

        return query, normalized_num_links, offset

    async def _execute_http_request(
        self,
        query: str,
        num_links: int,
        offset: int,
        result_filter: str,
        safesearch: bool,
        freshness: str | None,
        spellcheck: bool,
        language: str | None,
    ) -> Any:
        """Execute HTTP request to Brave Search API.

        This method performs the actual HTTP call without retry logic,
        allowing for easier testing and mocking.

View on GitHub (pinned to 4a030776a3)