unslothai/unsloth · error · ValueError

offset must be non-negative

Error message

offset must be non-negative

What it means

Raised by list_chat_attachments_page() in the studio chat attachment inventory API when the pagination offset is negative. The function is a bounded paging wrapper (limit 1-100, offset >= 0) over the normalized chat_attachment_inventory table, and it validates its arguments before touching SQLite. A negative offset can only come from the caller, never from the database.

Source

Thrown at studio/backend/storage/studio_db.py:3296

                "type": kind,
                "name": part_name
                if isinstance(part_name, str) and part_name
                else ("Chat image" if kind == "image" else "Chat audio"),
                "contentType": content_type,
                "content": [part],
            }
        )
    return out


def list_chat_attachments_page(
    limit: int = 50, offset: int = 0
) -> tuple[list[dict], Optional[int]]:
    """One bounded page from the normalized attachment inventory."""
    if not 1 <= limit <= 100:
        raise ValueError("limit must be between 1 and 100")
    if offset < 0:
        raise ValueError("offset must be non-negative")

    conn = get_connection()
    try:
        _ensure_chat_attachment_inventory_current(conn)
        rows = conn.execute(
            """
            SELECT i.attachment_id, i.name, i.type, i.content_type,
                   i.size_bytes, m.id AS message_id, m.thread_id,
                   m.created_at, t.title AS thread_title, t.pair_id
            FROM chat_attachment_inventory i
            JOIN chat_messages m ON m.id = i.message_id
            LEFT JOIN chat_threads t ON t.id = m.thread_id
            ORDER BY m.created_at DESC, m.id ASC, i.attachment_id ASC
            LIMIT ? OFFSET ?
            """,
            (limit + 1, offset),
        ).fetchall()
    finally:

View on GitHub (pinned to 203007d190)

Solutions

  1. Clamp the offset before calling: offset = max(0, offset)
  2. If the offset is derived from a page number, validate page >= 1 before computing (page - 1) * limit
  3. Return an HTTP 422/400 to the client instead of letting the ValueError escape when the offset comes from user input

Example fix

// before
offset = (page - 1) * limit
rows, total = list_chat_attachments_page(limit=limit, offset=offset)

// after
if page < 1:
    raise HTTPException(422, "page must be >= 1")
offset = (page - 1) * limit
rows, total = list_chat_attachments_page(limit=limit, offset=offset)
Defensive patterns

Strategy: validation

Validate before calling

def safe_page_params(page: int, limit: int) -> tuple[int, int]:
    if page < 1:
        raise ValueError("page must be >= 1")
    if not 1 <= limit <= 100:
        raise ValueError("limit must be between 1 and 100")
    offset = (page - 1) * limit
    return limit, max(0, offset)

Type guard

def is_valid_offset(offset: int) -> bool:
    return isinstance(offset, int) and offset >= 0

Try / catch

try:
    rows, total = list_chat_attachments_page(limit=limit, offset=offset)
except ValueError as e:
    # map to a 4xx for user-supplied paging params
    raise HTTPException(status_code=422, detail=str(e))

Prevention

When it happens

Trigger: Calling list_chat_attachments_page(limit=50, offset=-1) or any negative offset, typically the result of page arithmetic like (page - 1) * limit when the caller passed page=0 or an unvalidated page number from an HTTP query string.

Common situations: HTTP handlers mapping ?page=N to offset = (page-1)*limit; CLI tools accepting a --skip argument; off-by-one bugs when page numbering starts at 0 but the formula assumes 1-based pages.

Related errors


AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15). Data as JSON: /api/errors/eef32d2c9839b36d. Report an issue: GitHub.