From 421ea383563cbe0964cf533fcd0053e4ad00e61c Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Sat, 12 Sep 2026 23:30:01 -0700 Subject: [PATCH] fix(mobile): stop crashing on launch before the shell snapshot arrives Build 56 still died on every cold open. The device's expo-error.log names it: "TypeError: Cannot read property 'defaultModelSelection' of null" in NewTaskFlowProvider. resolveProjectSettings reads the project aggregate's legacy fields when projectSettingsFolded is false, and the mobile flow passes its selected project through as-is, which is null until the shell snapshot lands. tsc did not catch it: apps/mobile extends Expo's tsconfig without noUncheckedIndexedAccess, so `projects[0] ?? null` types as non-null there. Accept null in resolveProjectSettings and treat it like an absent project. Co-Authored-By: Claude Code --- packages/shared/src/projectSettings.test.ts | 8 ++++++++ packages/shared/src/projectSettings.ts | 6 ++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/shared/src/projectSettings.test.ts b/packages/shared/src/projectSettings.test.ts index 950867d36dc7..8760433182d6 100644 --- a/packages/shared/src/projectSettings.test.ts +++ b/packages/shared/src/projectSettings.test.ts @@ -29,6 +29,14 @@ describe("resolveProjectSettings", () => { ); }); + it("treats a null project like an absent one before the shell snapshot arrives", () => { + // The mobile new-task flow resolves settings while its selected project is + // still null; reading the aggregate's legacy fields off null crashed launch. + expect(resolveProjectSettings(DEFAULT_SERVER_SETTINGS, null, null).settings).toBe( + DEFAULT_SERVER_SETTINGS, + ); + }); + it("applies overrides per key and reports their source", () => { const settings = applyServerSettingsPatch(DEFAULT_SERVER_SETTINGS, { defaultAutoPull: true, diff --git a/packages/shared/src/projectSettings.ts b/packages/shared/src/projectSettings.ts index 742e1cb8d140..edb56654f5d0 100644 --- a/packages/shared/src/projectSettings.ts +++ b/packages/shared/src/projectSettings.ts @@ -59,11 +59,13 @@ export interface LegacyProjectSettingsFields { export function resolveProjectSettings( settings: ServerSettings, projectId: ProjectId | null, - project?: LegacyProjectSettingsFields, + // Nullable, not just optional: the mobile new-task flow passes its selected + // project straight through, and that is null until the shell snapshot lands. + project?: LegacyProjectSettingsFields | null, ): ResolvedProjectSettings { const stored = projectId === null ? undefined : settings.projectSettingsOverrides[projectId]; const overrides: ProjectSettingsOverrides = - project === undefined || settings.projectSettingsFolded + project == null || settings.projectSettingsFolded ? (stored ?? EMPTY_OVERRIDES) : { ...(project.defaultModelSelection != null