{"record":{"id":"aa4272384a213bb6","repo":"gitbutlerapp/gitbutler","slug":"could-not-find-selected-project","errorCode":null,"errorMessage":"Could not find selected project","messagePattern":"Could not find selected project","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/lite/ui/src/routes/project/$id/workspace/useHunkMenuItems.ts","lineNumber":54,"sourceCode":"\tcheckedProbe: Extract<Address, { _tag: \"Hunk\" }> | null;\n\tusesSelectedLines: boolean;\n};\n\nexport const useHunkMenuItems = ({\n\tprojectId,\n}: {\n\tprojectId: string;\n}): ((target: HunkMenuTarget) => Array<NativeMenuItem>) => {\n\tconst store = useAppStore();\n\tconst { data: projects } = useSuspenseQuery(listProjectsQueryOptions);\n\tconst { data: editors } = useQuery(listEditorsQueryOptions);\n\tconst { data: preferredEditor } = useQuery({\n\t\t...guiSettingsQueryOptions,\n\t\tselect: (cfg) => editors?.find((editor) => editor.id === cfg.editorId),\n\t});\n\n\tconst selectedProject = projects.find((project) => project.id === projectId);\n\tif (!selectedProject) throw new Error(\"Could not find selected project\");\n\n\tconst { isPending: isCommitUncommitChangesPending, mutate: commitUncommitChanges } =\n\t\tuseCommitUncommitChanges();\n\tconst { isPending: isCommitDiscardChangesPending, mutate: commitDiscardChanges } =\n\t\tuseCommitDiscardChanges();\n\tconst { isPending: isDiscardWorktreeChangesPending, mutate: discardWorktreeChanges } =\n\t\tuseDiscardWorktreeChanges();\n\tconst { isPending: isOpenInProgramPending, mutate: openInProgram } = useOpenInProgram();\n\tconst revealInFolder = useRevealInFolder(projectId);\n\n\treturn ({ sources, checkedProbe, usesSelectedLines, change, hunk, lineNumber }) => {\n\t\tconst state = store.getState();\n\t\tconst usesCheckedLines =\n\t\t\tcheckedProbe !== null &&\n\t\t\tprojectSlice.selectors.selectAddressChecked(state, projectId, checkedProbe);\n\t\tconst cutSources = usesCheckedLines\n\t\t\t? projectSlice.selectors.selectCheckedAddresses(state, projectId)\n\t\t\t: sources;","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/apps/lite/ui/src/routes/project/$id/workspace/useHunkMenuItems.ts#L36-L72","documentation":"useHunkMenuItems looks up the project matching the projectId route param from the cached projects list and throws synchronously when none matches. This is an internal invariant: the hook's menu-item construction cannot proceed without a valid project. It guards against building hunk actions (commit/discard/uncommit) against a nonexistent project.","triggerScenarios":"Calling useHunkMenuItems(projectId) while the projects query cache does not contain a project whose id equals projectId — e.g. the project was removed, the list query hasn't resolved yet, or the route id is stale/invalid.","commonSituations":"A project is deleted in another window/instance while a workspace route for it is open; deep-linking to /project/<bad-id>/workspace; the projects list query failing or still loading so the cache is empty; using a stale bookmarked id after re-cloning.","solutions":["Verify the projectId route param matches an existing project id in the projects list (log both to compare).","Gate the hook/route behind the list-projects query's isLoading state so it only runs once projects are loaded.","If the project was deleted, navigate the user back to the project list instead of rendering the workspace route.","Refresh the projects list (invalidate listProjectsQueryOptions) if another client may have changed it."],"exampleFix":"// before\nconst selectedProject = projects.find((project) => project.id === projectId);\nif (!selectedProject) throw new Error(\"Could not find selected project\");\n\n// after\nconst selectedProject = projects.find((project) => project.id === projectId);\nuseEffect(() => {\n  if (!selectedProject && !isProjectsLoading) {\n    navigate({ to: \"/\" }); // leave the stale project route\n  }\n}, [selectedProject, isProjectsLoading]);","handlingStrategy":"validation","validationCode":"const projects = useQuery(listProjectsQueryOptions).data ?? [];\nconst canRender = projects.some((p) => p.id === projectId);","typeGuard":"const hasProject = (projects: Project[], id: string): projects is [Project, ...Project[]] & Project[] =>\n  projects.some((p) => p.id === id);","tryCatchPattern":"try {\n  const items = buildHunkMenuItems(projectId, ...);\n} catch (e) {\n  if (e instanceof Error && e.message === \"Could not find selected project\") {\n    navigate({ to: \"/\" });\n  } else throw e;\n}","preventionTips":["Gate workspace routes on the projects query's success state.","Redirect away from routes whose project id no longer exists.","Invalidate the projects query after mutations that add/remove projects."],"tags":["react","state","frontend"],"backgroundTag":"entity-not-found","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}