HumanSignal/label-studio · error · ValidationError
Project must be an integer.
Error message
Project must be an integer.
What it means
get_hotkey_project in label_studio/users/hotkeys.py validates the project_id query parameter for the hotkeys endpoints: it must be a string of digits matching ^[1-9][0-9]*$ (a positive integer, no leading zeros). Otherwise it raises DRF ValidationError with a field-scoped detail {'project': 'Project must be an integer.'}, producing a 400 response.
Source
Thrown at label_studio/users/hotkeys.py:14
import re
from projects.models import Project
from rest_framework.exceptions import NotFound, PermissionDenied, ValidationError
PROJECT_ID_PATTERN = re.compile(r'^[1-9][0-9]*$')
def get_hotkey_project(user, project_id) -> Project | None:
if project_id is None:
return None
if not isinstance(project_id, str) or PROJECT_ID_PATTERN.fullmatch(project_id) is None:
raise ValidationError({'project': 'Project must be an integer.'}) from None
project_id = int(project_id)
project = Project.objects.filter(
pk=project_id,
organization=user.active_organization,
).first()
if project is None:
raise NotFound('Project not found.')
if not project.has_permission(user):
raise PermissionDenied('You do not have access to this project.')
return project
View on GitHub (pinned to 0b49e9b539)
Solutions
- Pass the project ID as a plain digit string without leading zeros, e.g. project=123
- Convert ints to str before calling get_hotkey_project: get_hotkey_project(user, str(project_id))
- Fix the frontend to send the numeric PK of the project, not a name/slug
- Strip whitespace and validate with re.fullmatch(r'[1-9][0-9]*', value) client-side
Example fix
// before get_hotkey_project(user, 42) # int -> 400 get_hotkey_project(user, "042") # leading zero -> 400 // after get_hotkey_project(user, "42")
Defensive patterns
Strategy: validation
Validate before calling
import re
PROJECT_ID = re.compile(r'^[1-9][0-9]*$')
assert isinstance(project_id, str) and PROJECT_ID.fullmatch(project_id), f'bad project id: {project_id!r}' Type guard
def is_valid_project_id(v):
return isinstance(v, str) and re.fullmatch(r'[1-9][0-9]*', v) is not None Try / catch
try:
project = get_hotkey_project(user, project_id)
except ValidationError as e:
if 'Project must be an integer.' in str(e.detail):
project = get_hotkey_project(user, str(int(project_id)))
else:
raise Prevention
- Pass project IDs as digit strings without leading zeros
- Convert ints to str before calling hotkey endpoints
- URL-encode query params and avoid stray whitespace
- Validate with ^[1-9][0-9]*$ client-side before the request
When it happens
Trigger: GET/PATCH /api/current-user/reset-token or hotkey routes with ?project=abc, ?project=1.5, ?project=0, ?project=01, ?project=%201 (whitespace), or passing an int-typed value in code so isinstance(project_id, str) fails — the function requires a string even for valid numbers.
Common situations: Frontend passing an unvalidated user-typed project ID; clients passing a Python int instead of str when calling the helper directly; URLs built from route params that can be '0' or non-numeric slugs; double-encoded or whitespace-padded query values.
Related errors
- Validation failed on {}: {}
- Label config contains non-unique names:
- toName="{toName}" not found in names: {sorted(names)}
- Can't resolve hostname {domain}
- Incorrect bool value "{value}". It should be one of [1, 0, t
AI-assisted analysis of HumanSignal/label-studio@0b49e9b539 (2026-08-29).
Data as JSON: /api/errors/ce770977f4485ede.
Report an issue: GitHub.