lfnovo/open-notebook · warning · InvalidInputError
Invalid order_by clause: '{clause.strip()}'
Error message
Invalid order_by clause: '{clause.strip()}' What it means
_validate_order_by() rejects multi-token clauses that are malformed: either the field fails the allowed-field pattern or the direction token isn't one of the allowed ASC/DESC keywords; clauses with 3+ tokens always hit this branch. It is the injection/validation guard for the order_by string that gets interpolated into SurrealQL.
Source
Thrown at open_notebook/domain/base.py:63
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_name
if cls.table_name:
target_class = cls
table_name = cls.table_name
else:
# This path is taken if called directly from ObjectModel
raise InvalidInputError(View on GitHub (pinned to a7de90d38a)
Solutions
- Format clauses strictly as '<field> asc|desc' (or bare field), comma-separated for multiple sorts
- Map UI sort choices to the two allowed direction keywords before calling get_all
- Whitelist the field against the model's fields and reject anything with extra tokens
Example fix
// before
order_by = f"{field} {direction}" # direction could be 'ascending'
// after
DIRS = {'asc': 'asc', 'ascending': 'asc', 'desc': 'desc', 'descending': 'desc'}
order_by = f"{field} {DIRS[direction.lower()]}" Defensive patterns
Strategy: validation
Validate before calling
DIRS = {'asc', 'desc'}
for clause in raw.split(','):
parts = clause.strip().lower().split()
ok = (len(parts) == 1 and parts[0] in allowed_fields) or \
(len(parts) == 2 and parts[0] in allowed_fields and parts[1] in DIRS)
if not ok:
raise InvalidInputError(f'Invalid order_by clause: {clause}') Type guard
def is_valid_order_clause(clause: str, allowed_fields: set[str]) -> bool:
parts = clause.strip().lower().split()
return ((len(parts) == 1 and parts[0] in allowed_fields) or
(len(parts) == 2 and parts[0] in allowed_fields and parts[1] in ('asc', 'desc'))) Try / catch
try:
items = await Model.get_all(order_by=raw)
except InvalidInputError:
items = await Model.get_all() # fall back to default ordering
Prevention
- Map UI sort selections to exactly '<field> asc|desc' before calling get_all
- Normalize common synonyms (ascending→asc) client-side
- Reject any clause with more than two tokens at the API boundary
When it happens
Trigger: Passing 'created_at ASC; DROP' (3+ tokens), 'created-at asc' (bad field), or 'created_at ascending' (direction not in allowed set); concatenating user input into order_by without normalizing; sending empty middle tokens like 'created_at asc extra'.
Common situations: Frontend building sort strings from multiple params; users typing free-text sort expressions; direction values like 'ascending'/'up' instead of 'asc'; injection attempts targeting the ORDER BY clause.
Related errors
- Invalid order_by field: '{parts[0]}'
- 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/a7e6e7a80ad4713d.
Report an issue: GitHub.