{"record":{"id":"6ff12147b6c45f42","repo":"block/buzz","slug":"choose-a-project","errorCode":null,"errorMessage":"Choose a project.","messagePattern":"Choose a project\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"desktop/src/features/projects/ui/ProjectsCategoryCreateDialogs.tsx","lineNumber":57,"sourceCode":"          channel.isMember &&\n          !channel.archivedAt &&\n          channel.channelType !== \"dm\",\n      ),\n    [channelsQuery.data],\n  );\n\n  return (\n    <>\n      <CreateChannelDialog\n        channelKind={channelOpen ? \"stream\" : null}\n        description={\n          channelProject\n            ? `Add another stream to ${channelProject.name}.`\n            : \"Choose a project for this channel.\"\n        }\n        isCreating={createChannelMutation.isPending}\n        onCreate={async (input) => {\n          if (!channelProject) throw new Error(\"Choose a project.\");\n          const result = await createChannelMutation.mutateAsync({\n            ...input,\n            ownerControlAgentPubkey: ownerControlAgentPubkeyFor(channelProject),\n            project: channelProject,\n          });\n          toast.success(`Channel \"#${result.channel.name}\" created.`);\n          await goChannel(result.channel.id);\n        }}\n        onOpenChange={onChannelOpenChange}\n        testId=\"create-project-channel-dialog\"\n        title=\"Create a project channel\"\n      >\n        <label className=\"block space-y-1.5 text-sm font-medium\">\n          <span>Project</span>\n          <select\n            className=\"h-10 w-full rounded-lg border border-input bg-background px-3 text-sm font-normal outline-hidden focus:ring-1 focus:ring-ring\"\n            data-testid=\"create-project-channel-project\"\n            disabled={createChannelMutation.isPending}","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/block/buzz/blob/eed74bde2f4797714335ac10c56c0b0244c1def4/desktop/src/features/projects/ui/ProjectsCategoryCreateDialogs.tsx#L39-L75","documentation":"The ProjectsCategoryCreateDialogs channel-creation flow throws this error to enforce an internal invariant: the dialog's create-channel callback should only be reachable when a project (`channelProject`) has already been selected for the channel. The surrounding UI text says 'Choose a project for this channel', and `onCreate` refuses to run the mutation when `channelProject` is null. Hitting this means the code path invoked without the project being resolved — the guard is a defensive assertion, not an expected user-facing error.","triggerScenarios":"Calling the dialog's `onCreate` handler while `channelProject` is null/undefined: the user (or a test/e2e harness) submits the create-channel form before a project is selected, or the project lookup that sets `channelProject` failed silently while the submit action remained enabled.","commonSituations":"UI state where the 'create channel' button is clickable before a project picker selection; a race where the project query has not resolved but the form is submitted; automated tests invoking onCreate without first choosing a project; channel project fetch failing (e.g. relay unreachable) leaving channelProject null.","solutions":["Select a project in the dialog's project picker before submitting the create-channel form.","Disable the submit button when `!channelProject` so the handler can never run without a project.","If `channelProject` should be derived automatically, verify the query/hook that sets it actually resolved and did not fail.","In tests, seed the project selection state before invoking onCreate."],"exampleFix":"// before\nonCreate={async (input) => {\n  if (!channelProject) throw new Error(\"Choose a project.\");\n  ...\n}}\n// after — prevent submission instead of throwing\n<button\n  disabled={!channelProject || createChannelMutation.isPending}\n  onClick={() => formRef.current?.requestSubmit()}\n/>\nonCreate={async (input) => {\n  if (!channelProject) return; // unreachable when button is disabled\n  ...\n}}","handlingStrategy":"validation","validationCode":"if (!channelProject) {\n  toast.error(\"Select a project before creating the channel.\");\n  return;\n}\nawait createChannelMutation.mutateAsync({ ...input, project: channelProject });","typeGuard":"const hasProject = (p: unknown): p is { id: string; name: string } =>\n  typeof p === \"object\" && p !== null && \"id\" in p && \"name\" in p;","tryCatchPattern":"try {\n  await createChannelMutation.mutateAsync({ ...input, project: channelProject! });\n} catch (e) {\n  if (e instanceof Error && e.message === \"Choose a project.\") {\n    toast.error(\"Select a project first.\");\n  } else throw e;\n}","preventionTips":["Disable the submit/create button while channelProject is null.","Surface the project picker as a required step in the dialog flow.","Write a test asserting onCreate is unreachable without a project selection."],"tags":["ui","validation","react","state-guard"],"backgroundTag":"missing-required-selection","analyzedSha":"eed74bde2f4797714335ac10c56c0b0244c1def4","analyzedAt":"2026-08-30T13:49:18.474Z","contentChangedAt":"2026-08-30T13:49:18.474Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}