{"record":{"id":"ce770977f4485ede","repo":"HumanSignal/label-studio","slug":"project-must-be-an-integer","errorCode":null,"errorMessage":"Project must be an integer.","messagePattern":"Project must be an integer\\.","errorType":"validation","errorClass":"ValidationError","httpStatus":400,"severity":"error","filePath":"label_studio/users/hotkeys.py","lineNumber":14,"sourceCode":"import re\n\nfrom projects.models import Project\nfrom rest_framework.exceptions import NotFound, PermissionDenied, ValidationError\n\nPROJECT_ID_PATTERN = re.compile(r'^[1-9][0-9]*$')\n\n\ndef get_hotkey_project(user, project_id) -> Project | None:\n    if project_id is None:\n        return None\n\n    if not isinstance(project_id, str) or PROJECT_ID_PATTERN.fullmatch(project_id) is None:\n        raise ValidationError({'project': 'Project must be an integer.'}) from None\n\n    project_id = int(project_id)\n    project = Project.objects.filter(\n        pk=project_id,\n        organization=user.active_organization,\n    ).first()\n    if project is None:\n        raise NotFound('Project not found.')\n    if not project.has_permission(user):\n        raise PermissionDenied('You do not have access to this project.')\n    return project\n","sourceCodeStart":1,"sourceCodeEnd":26,"githubUrl":"https://github.com/HumanSignal/label-studio/blob/0b49e9b53917880baf1dd85d574fe5541a9aafb2/label_studio/users/hotkeys.py#L1-L26","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nget_hotkey_project(user, 42)          # int -> 400\nget_hotkey_project(user, \"042\")       # leading zero -> 400\n// after\nget_hotkey_project(user, \"42\")","handlingStrategy":"validation","validationCode":"import re\nPROJECT_ID = re.compile(r'^[1-9][0-9]*$')\nassert isinstance(project_id, str) and PROJECT_ID.fullmatch(project_id), f'bad project id: {project_id!r}'","typeGuard":"def is_valid_project_id(v):\n    return isinstance(v, str) and re.fullmatch(r'[1-9][0-9]*', v) is not None","tryCatchPattern":"try:\n    project = get_hotkey_project(user, project_id)\nexcept ValidationError as e:\n    if 'Project must be an integer.' in str(e.detail):\n        project = get_hotkey_project(user, str(int(project_id)))\n    else:\n        raise","preventionTips":["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"],"tags":["validation","query-params","hotkeys","http-400"],"backgroundTag":"invalid-query-parameter","analyzedSha":"0b49e9b53917880baf1dd85d574fe5541a9aafb2","analyzedAt":"2026-08-29T00:39:52.578Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}