From 3349fb95ca5422d10fbd8064ece7a3c384b146be Mon Sep 17 00:00:00 2001
From: LukeParkerDev <10430890+Hona@users.noreply.github.com>
Date: Fri, 17 Apr 2026 14:52:06 +1000
Subject: [PATCH] fix(layout): guard SortableWorkspace against undefined
project during server swap
bootstrapDirectory's setStore fires while a server swap is cascading; currentProject() can already be undefined by the time these memos re-run, which threw 'Cannot read properties of undefined (reading worktree)' from local/workspaceValue/WorkspaceActions root. Optional-chain the props.project reads so the component survives the transient undefined before the enclosing Show unmounts it.
---
.../app/src/pages/layout/sidebar-workspace.tsx | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/packages/app/src/pages/layout/sidebar-workspace.tsx b/packages/app/src/pages/layout/sidebar-workspace.tsx
index e3b0ccd77c..b6685d35d7 100644
--- a/packages/app/src/pages/layout/sidebar-workspace.tsx
+++ b/packages/app/src/pages/layout/sidebar-workspace.tsx
@@ -319,12 +319,20 @@ export const SortableWorkspace = (props: {
})
const slug = createMemo(() => base64Encode(props.directory))
const sessions = createMemo(() => sortedRootSessions(workspaceStore, props.sortNow()))
- const local = createMemo(() => props.directory === props.project.worktree)
+ // Guard against `props.project` being transiently undefined during a
+ // server-switch cascade. The parent renders
+ // {(dir) => }
+ // where `project()` can flip to undefined while the enclosing
+ // gate hasn't yet unmounted this child. Bootstrap's setStore can then fire
+ // these memos with stale props.
+ const local = createMemo(() => props.directory === (props.project?.worktree ?? ""))
const active = createMemo(() => workspaceKey(props.ctx.currentDir()) === workspaceKey(props.directory))
const workspaceValue = createMemo(() => {
const branch = workspaceStore.vcs?.branch
const name = branch ?? getFilename(props.directory)
- return props.ctx.workspaceName(props.directory, props.project.id, branch) ?? name
+ const projectId = props.project?.id
+ if (!projectId) return name
+ return props.ctx.workspaceName(props.directory, projectId, branch) ?? name
})
const open = createMemo(() => props.ctx.workspaceExpanded(props.directory, local()))
const boot = createMemo(() => open() || active())
@@ -423,7 +431,7 @@ export const SortableWorkspace = (props: {
openEditor={props.ctx.openEditor}
showResetWorkspaceDialog={props.ctx.showResetWorkspaceDialog}
showDeleteWorkspaceDialog={props.ctx.showDeleteWorkspaceDialog}
- root={props.project.worktree}
+ root={props.project?.worktree ?? props.directory}
clearHoverProjectSoon={props.ctx.clearHoverProjectSoon}
navigateToNewSession={() => navigate(`/${slug()}/session`)}
/>