lfnovo/open-notebook · warning · HTTPException
Invalid order_by: '{order_by}'. Allowed fields: {', '.join(s
Error message
Invalid order_by: '{order_by}'. Allowed fields: {', '.join(sorted(allowed_fields))}. Allowed directions: asc, desc What it means
400 from GET /api/v1/notebooks when order_by has two words but either the field is not allowed or the direction is not 'asc'/'desc'. Note the direction check is case-sensitive on the lowercased parts only insofar as the whole string was lowercased, so 'Created ASC' works but 'created ascending' or 'name descending' fails.
Source
Thrown at api/routers/notebooks.py:82
order_by: str = Query("updated desc", description="Order by field and direction"),
):
"""Get all notebooks with optional filtering and ordering."""
try:
# Validate order_by against allowlist to prevent SurrealQL injection
allowed_fields = {"name", "created", "updated"}
allowed_directions = {"asc", "desc"}
parts = order_by.strip().lower().split()
if len(parts) == 1:
if parts[0] not in allowed_fields:
raise HTTPException(
status_code=400,
detail=f"Invalid order_by field: '{order_by}'. Allowed fields: {', '.join(sorted(allowed_fields))}",
)
validated_order_by = parts[0]
elif len(parts) == 2:
if parts[0] not in allowed_fields or parts[1] not in allowed_directions:
raise HTTPException(
status_code=400,
detail=f"Invalid order_by: '{order_by}'. Allowed fields: {', '.join(sorted(allowed_fields))}. Allowed directions: asc, desc",
)
validated_order_by = f"{parts[0]} {parts[1]}"
else:
raise HTTPException(
status_code=400,
detail=f"Invalid order_by format: '{order_by}'. Expected 'field' or 'field direction'",
)
# Build the query with counts
query = f"""
SELECT *,
count(<-reference.in) as source_count,
count(<-artifact.in) as note_count
FROM notebook
ORDER BY {validated_order_by}
"""View on GitHub (pinned to a7de90d38a)
Solutions
- Use exactly 'asc' or 'desc' (they're lowercased with the input, so case is safe) after an allowed field
- Drop the direction to use the default sort
- Validate order_by client-side against the allow-list before calling
Example fix
// before GET /api/v1/notebooks?order_by=updated descending // after GET /api/v1/notebooks?order_by=updated desc
Defensive patterns
Strategy: validation
Validate before calling
const m = order_by.trim().toLowerCase().match(/^(name|created|updated)( (asc|desc))?$/); if (!m) order_by = 'created desc'; // normalize instead of erroring
Type guard
const isValidOrderBy2 = (s: string) => /^(name|created|updated)( asc| desc)?$/.test(s.trim().toLowerCase());
Try / catch
try { await api.getNotebooks({order_by: q}); } catch (e) { if (e.status === 400 && /Allowed directions/.test(e.detail)) refetchSorted('created desc'); } Prevention
- Use only asc/desc abbreviations
- Map UI 'Ascending/Descending' labels to asc/desc before sending
- Validate with a shared regex on both field and direction
When it happens
Trigger: GET /notebooks?order_by=created ascending, ?order_by=title desc, or ?order_by=name descending — wrong direction word or disallowed field with a direction.
Common situations: Sort UI sending full direction words; typos in direction; combining a bad field with a valid direction.
Related errors
- Invalid order_by field: '{order_by}'. Allowed fields: {', '.
- No embedding model configured. Please configure one in the M
- Item type must be either 'source' or 'note'
- Invalid model type. Must be one of: {valid_types}
- {field} is required and cannot be cleared, only reassigned
AI-assisted analysis of lfnovo/open-notebook@a7de90d38a (2026-08-27).
Data as JSON: /api/errors/f3a2d646a0f82ad6.
Report an issue: GitHub.