{"record":{"id":"b520ee3ab13e79c9","repo":"HumanSignal/label-studio","slug":"project-not-found","errorCode":null,"errorMessage":"Project not found.","messagePattern":"Project not found\\.","errorType":"http","errorClass":"NotFound","httpStatus":404,"severity":"error","filePath":"label_studio/users/hotkeys.py","lineNumber":22,"sourceCode":"from 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":4,"sourceCodeEnd":26,"githubUrl":"https://github.com/HumanSignal/label-studio/blob/0b49e9b53917880baf1dd85d574fe5541a9aafb2/label_studio/users/hotkeys.py#L4-L26","documentation":"get_hotkey_project raises DRF NotFound after the ID format check when no Project matches both the given pk and the user's active organization. The lookup is scoped to the active organization, so a valid project ID from a different organization also yields 404 'Project not found.'","triggerScenarios":"GET/PATCH hotkey endpoints with ?project=<id> where the ID doesn't exist, was deleted, or belongs to another organization than the user's active_organization (multi-org users switching orgs while caching old IDs).","commonSituations":"Stale project IDs in frontend state after a project was deleted; users in multiple organizations whose active org changed (via UI switch or /api/current-user org switch) so previously valid IDs are invisible; copied URLs/bookmarks referencing projects from another org; typos in the project ID.","solutions":["Verify the project ID exists and belongs to the user's currently active organization","Switch the user's active organization to the one owning the project (PATCH /api/current-user with the org id or the org-switch endpoint)","Refresh the frontend's project list and use a current project ID instead of a cached one","Check the project wasn't deleted; list projects via GET /api/projects/ under the active org to find a valid ID"],"exampleFix":"// before\nGET /api/hotkeys?project=999   # project lives in another org -> 404\n// after\n# switch to the org that owns the project, then\nGET /api/hotkeys?project=999","handlingStrategy":"try-catch","validationCode":"existing = [p.id for p in client.projects.list()]\nif project_id not in existing:\n    raise ValueError(f'project {project_id} not visible in active organization')","typeGuard":"def project_in_active_org(project, user):\n    return project is not None and project.organization_id == user.active_organization_id","tryCatchPattern":"try:\n    project = get_hotkey_project(user, project_id)\nexcept NotFound:\n    logger.warning('Project %s not found in active org; refreshing project list', project_id)\n    projects = client.projects.list()\n    project = next((p for p in projects if p.id == project_id), None)\n    if project is None:\n        raise","preventionTips":["Re-fetch project IDs after switching active organization","Handle 404 on hotkey/project routes by refreshing the project list","Check the project still exists before deep-linking to it","Remember lookups are scoped to the active organization — a valid ID elsewhere still 404s"],"tags":["http-404","hotkeys","multi-tenancy","rest-api"],"backgroundTag":"resource-not-found","analyzedSha":"0b49e9b53917880baf1dd85d574fe5541a9aafb2","analyzedAt":"2026-08-29T00:39:52.578Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}