jamiepine/voicebox · warning · HTTPException

limit must be between 1 and 200

Error message

limit must be between 1 and 200

What it means

Returned as a 400 from GET /captures when the `limit` query param is outside [1, 200]. The route hard-validates limit before calling list_captures because the list endpoint must stay bounded — an unbounded or zero limit would either return nothing or attempt to load the entire table. This is a static guard, independent of service logic.

Source

Thrown at backend/routes/captures.py:77

    except Exception as e:
        logger.exception("Failed to create capture")
        raise HTTPException(status_code=500, detail=str(e))

    return models.CaptureCreateResponse(
        **capture.model_dump(),
        auto_refine=bool(saved.auto_refine),
        allow_auto_paste=bool(saved.allow_auto_paste),
    )


@router.get("/captures", response_model=models.CaptureListResponse)
async def list_captures_endpoint(
    limit: int = 50,
    offset: int = 0,
    db: Session = Depends(get_db),
):
    if limit < 1 or limit > 200:
        raise HTTPException(status_code=400, detail="limit must be between 1 and 200")
    if offset < 0:
        raise HTTPException(status_code=400, detail="offset must be >= 0")

    items, total = captures_service.list_captures(db, limit=limit, offset=offset)
    return models.CaptureListResponse(items=items, total=total)


@router.get("/captures/{capture_id}", response_model=models.CaptureResponse)
async def get_capture_endpoint(capture_id: str, db: Session = Depends(get_db)):
    capture = captures_service.get_capture(capture_id, db)
    if not capture:
        raise HTTPException(status_code=404, detail="Capture not found")
    return capture


@router.get("/captures/{capture_id}/audio")
async def get_capture_audio_endpoint(capture_id: str, db: Session = Depends(get_db)):
    """Stream the original capture audio file."""

View on GitHub (pinned to 51f49dea19)

Solutions

  1. Clamp limit to [1, 200] on the client before building the query string.
  2. Use the default (omit limit) for normal list views.
  3. If you genuinely need more than 200, paginate with offset instead of inflating limit.

Example fix

// before
fetch(`/captures?limit=${requested}`) // requested may be 0 or 1000
// after
const limit = Math.min(200, Math.max(1, requested || 50));
fetch(`/captures?limit=${limit}`)
Defensive patterns

Strategy: validation

Validate before calling

const limit = Math.min(200, Math.max(1, Number(reqLimit) || 50));
fetch(`/captures?limit=${limit}`);

Type guard

function isValidLimit(n: number): boolean {
  return Number.isInteger(n) && n >= 1 && n <= 200;
}

Prevention

When it happens

Trigger: GET /captures?limit=0, GET /captures?limit=201, or GET /captures?limit=-5 (a negative int parsed by FastAPI). Also limit omitted is fine (default 50).

Common situations: Frontend pagination bug passing limit=0 to mean 'no items'; a UI control allowing values above 200; a script scraping with limit=1000.

Related errors


AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12). Data as JSON: /api/errors/d311f54527713842. Report an issue: GitHub.