lfnovo/open-notebook · warning · InvalidInputError
Invalid order_by field: '{parts[0]}'
Error message
Invalid order_by field: '{parts[0]}' What it means
_validate_order_by() parses a user-supplied order_by string into field/direction clauses; a single-token clause whose field doesn't match the allowed field pattern raises InvalidInputError('Invalid order_by field: ...'). This is an injection guard — order_by is interpolated into SurrealQL, so only whitelisted field names (and ASC/DESC directions) survive.
Source
Thrown at open_notebook/domain/base.py:57
@classmethod
def _validate_order_by(cls, order_by: str) -> str:
"""Validate and normalize an ORDER BY clause to prevent SurrealQL injection.
Supports: "field", "field direction", "field1 direction, field2 direction".
Any subclass that builds its own query around `order_by` (instead of
delegating to `get_all()`) must route through this so the allowlist
can't silently drift between call sites.
"""
allowed_field_pattern = re.compile(r"^[a-z_][a-z0-9_]*$")
allowed_directions = {"asc", "desc"}
clauses = [c.strip() for c in order_by.split(",")]
validated_clauses = []
for clause in clauses:
parts = clause.strip().split()
if len(parts) == 1:
if not allowed_field_pattern.match(parts[0].lower()):
raise InvalidInputError(f"Invalid order_by field: '{parts[0]}'")
validated_clauses.append(parts[0].lower())
elif len(parts) == 2:
if not allowed_field_pattern.match(
parts[0].lower()
) or parts[1].lower() not in allowed_directions:
raise InvalidInputError(
f"Invalid order_by clause: '{clause.strip()}'"
)
validated_clauses.append(f"{parts[0].lower()} {parts[1].lower()}")
else:
raise InvalidInputError(f"Invalid order_by clause: '{clause.strip()}'")
return ", ".join(validated_clauses)
@classmethod
async def get_all(cls: Type[T], order_by=None) -> List[T]:
try:
# If called from a specific subclass, use its table_nameView on GitHub (pinned to a7de90d38a)
Solutions
- Use only real, whitelisted field names from the model's allowed fields — check the model class for the permitted pattern
- Fix typos/case: fields are matched lowercased, so send lowercase snake_case names
- If exposing order_by via API, validate it against the model's field list before calling get_all
Example fix
// before
Note.get_all(order_by=request.query_params['sort'])
// after
allowed = {'created_at', 'updated_at', 'title'}
sort = request.query_params.get('sort', 'created_at')
if sort.lstrip('-').split(' ')[0] not in allowed:
raise InvalidInputError(f'Invalid order_by field: {sort}')
Note.get_all(order_by=sort) Defensive patterns
Strategy: validation
Validate before calling
allowed = get_allowed_order_fields(Note) # from the model
raw = request.query_params.get('order_by', '')
for clause in raw.split(','):
field = clause.strip().split()[0].lower()
if field not in allowed:
raise InvalidInputError(f'Invalid order_by field: {field}') Type guard
def is_valid_order_by(order_by: str, allowed_fields: set[str]) -> bool:
for clause in order_by.split(','):
parts = clause.strip().lower().split()
if not parts or parts[0] not in allowed_fields:
return False
if len(parts) == 2 and parts[1] not in ('asc', 'desc'):
return False
if len(parts) > 2:
return False
return True Try / catch
try:
items = await Model.get_all(order_by=raw)
except InvalidInputError:
return JSONResponse(400, 'invalid order_by') Prevention
- Never pass raw query params as order_by — whitelist first
- Keep frontend sort keys in sync with model field names
- Return the allowed-fields list to clients so they can validate locally
When it happens
Trigger: Calling get_all(order_by='created; REMOVE TABLE notes') or any single-token clause with punctuation, spaces, or a leading digit; requesting a field not in the model's allowed fields (e.g. ordering notes by 'foo_bar'); passing raw query params straight from the API to get_all.
Common situations: Frontend sending a sort field the backend model doesn't define; typos in sort keys ('creatd_at'); attempts at SurrealQL injection through the sort parameter; renaming a model field without updating sort options in the UI.
Related errors
- Invalid order_by clause: '{clause.strip()}'
- Invalid {kind} name: {value!r}
- 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}
AI-assisted analysis of lfnovo/open-notebook@a7de90d38a (2026-08-27).
Data as JSON: /api/errors/ee74663703b8de53.
Report an issue: GitHub.