{"record":{"id":"c19c2a8fd723cc1e","repo":"gitbutlerapp/gitbutler","slug":"could-not-find-selected-project-userevealinfolder","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/useRevealInFolder.ts","lineNumber":18,"sourceCode":"import { listProjectsQueryOptions } from \"#ui/api/queries.ts\";\nimport { useQueryClient } from \"@tanstack/react-query\";\n\n/**\n * Reveals a repository-relative path in the OS file manager. Only the\n * project's location turns that path absolute, so it is resolved here rather\n * than at each of the surfaces — file rows, hunks, the diff — that offer the\n * action. The list is read when the action runs rather than subscribed to:\n * nothing here renders it, and a surface that suspended on it would tear down\n * the very rows it lists.\n */\nexport const useRevealInFolder = (projectId: string): ((path: string) => Promise<void>) => {\n\tconst queryClient = useQueryClient();\n\n\treturn async (path) => {\n\t\tconst projects = queryClient.getQueryData(listProjectsQueryOptions.queryKey);\n\t\tconst projectPath = projects?.find((project) => project.id === projectId)?.path;\n\t\tif (projectPath === undefined) throw new Error(\"Could not find selected project\");\n\n\t\tconst absolutePath = await window.lite.pathJoin(projectPath, path);\n\t\tawait window.lite.showItemInFolder(absolutePath);\n\t};\n};\n","sourceCodeStart":1,"sourceCodeEnd":24,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/apps/lite/ui/src/routes/project/$id/workspace/useRevealInFolder.ts#L1-L24","documentation":"useRevealInFolder returns a callback that reads the projects list directly from the query cache via queryClient.getQueryData and looks up projectId. If the cache holds no such project (or no data at all), the project's path can't be resolved and the callback throws instead of revealing a nonexistent location in the file manager.","triggerScenarios":"Calling the returned reveal(path) function when the listProjects query data is absent from the cache or contains no project with the given id — e.g. cache evicted, query never fetched, project deleted, or a wrong projectId passed in.","commonSituations":"Clicking 'Reveal in folder' right after app start before projects are fetched; project was deleted in another instance; projectId mismatch after a route/data refactor; getQueryData returning undefined because the observer wasn't mounted anywhere.","solutions":["Ensure the listProjects query has been fetched (or prefetch it) before enabling the reveal action.","Check that the projectId passed to useRevealInFolder matches a project in the cached list.","Handle the throw at the call site with a user-facing message instead of an unhandled rejection.","Use a useQuery hook (not raw getQueryData) so loading state is known before the action is available."],"exampleFix":"// before\nconst projects = queryClient.getQueryData(listProjectsQueryOptions.queryKey);\nconst projectPath = projects?.find((project) => project.id === projectId)?.path;\nif (projectPath === undefined) throw new Error(\"Could not find selected project\");\n\n// after\nconst { data: projects } = useQuery(listProjectsQueryOptions);\nconst projectPath = projects?.find((project) => project.id === projectId)?.path;\nconst reveal = useCallback(async (path: string) => {\n  if (!projectPath) return; // silently no-op when project is unavailable\n  const absolutePath = await window.lite.pathJoin(projectPath, path);\n  await window.lite.showItemInFolder(absolutePath);\n}, [projectPath]);","handlingStrategy":"fallback","validationCode":"const projects = queryClient.getQueryData<Project[]>(listProjectsQueryOptions.queryKey);\nconst projectPath = projects?.find((p) => p.id === projectId)?.path;\nif (projectPath === undefined) return; // skip action before invoking","typeGuard":"const resolveProjectPath = (projects: unknown, id: string): string | undefined =>\n  Array.isArray(projects)\n    ? (projects as { id: string; path?: string }[]).find((p) => p.id === id)?.path\n    : undefined;","tryCatchPattern":"try {\n  await reveal(path);\n} catch (e) {\n  if (e instanceof Error && e.message === \"Could not find selected project\") {\n    toast.error(\"Project is no longer available\");\n  } else throw e;\n}","preventionTips":["Prefer useQuery hooks over raw getQueryData so loading/absence states are explicit.","Disable the reveal action until projects data is in the cache.","Handle async action errors with a user-visible toast instead of letting rejections go unhandled."],"tags":["react","query-cache","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"}