{"record":{"id":"13389a79c1550d76","repo":"QuantumNous/new-api","slug":"no-channel-selected","errorCode":null,"errorMessage":"No channel selected","messagePattern":"No channel selected","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"web/src/features/channels/components/drawers/channel-mutate-drawer.tsx","lineNumber":1468,"sourceCode":"      const key = form.getValues('key')\n      if (!key?.trim()) {\n        toast.error(t('Please enter API key first'))\n        return\n      }\n    }\n\n    setFetchModelsDialogOpen(true)\n  }, [isEditing, canEditSensitive, form, t])\n\n  const formPreviewFetcher = useCallback(async (): Promise<string[]> => {\n    if (!canEditSensitive) {\n      throw new Error(t(\"You don't have necessary permission\"))\n    }\n    const type = form.getValues('type')\n    const editingAdvancedCustom =\n      isEditing && type === CHANNEL_TYPE_ADVANCED_CUSTOM\n    if (editingAdvancedCustom && channelId === null) {\n      throw new Error(t('No channel selected'))\n    }\n    const response = await fetchModels({\n      type,\n      key: isEditing ? undefined : form.getValues('key'),\n      channel_id: editingAdvancedCustom ? channelId || undefined : undefined,\n      base_url: form.getValues('base_url') || '',\n      advanced_custom: form.getValues('advanced_custom'),\n      header_override: form.getValues('header_override'),\n      proxy: form.getValues('proxy'),\n    })\n    if (response.success && response.data) {\n      return response.data\n    }\n    throw new Error(response.message || t('No models fetched from upstream'))\n  }, [canEditSensitive, channelId, form, isEditing, t])\n\n  // Handle model operations\n  const handleFillRelatedModels = useCallback(() => {","sourceCodeStart":1450,"sourceCodeEnd":1486,"githubUrl":"https://github.com/QuantumNous/new-api/blob/e2c7aa7b102c2075eae2377df3508658d45e88dc/web/src/features/channels/components/drawers/channel-mutate-drawer.tsx#L1450-L1486","documentation":"Thrown by formPreviewFetcher when editing an advanced-custom channel (isEditing && type === CHANNEL_TYPE_ADVANCED_CUSTOM) but channelId is null. Fetching models for advanced custom channels must be proxied through the saved channel (channel_id), so a missing id is rejected before calling fetchModels.","triggerScenarios":"Edit-mode drawer for an advanced custom channel where the id prop was not provided or was reset to null (e.g. state reused from create mode), then the user opens the fetch-models preview.","commonSituations":"Drawer opened programmatically without the row id; create/edit mode switch left channelId null; id lost during a refactor of the drawer's props.","solutions":["Ensure the edit drawer always receives the channel's id from the selected row","Reset and re-open the drawer from the channel table so state initializes correctly","Guard the UI: disable fetch-models when editingAdvancedCustom && channelId == null","Verify the parent passes a number id (not a string 'undefined'/'null' from URL params)"],"exampleFix":"// before\nif (editingAdvancedCustom && channelId === null) {\n  throw new Error(t('No channel selected'))\n}\n// after - prevent reaching the fetcher at all\nconst canFetchModels =\n  canEditSensitive &&\n  !(editingAdvancedCustom && channelId == null)\n// <Button disabled={!canFetchModels} ...>","handlingStrategy":"validation","validationCode":"const editingAdvancedCustom = isEditing && type === CHANNEL_TYPE_ADVANCED_CUSTOM\nif (editingAdvancedCustom && channelId == null) {\n  toast.error(t('No channel selected'))\n  return\n}","typeGuard":"const hasSavedChannel = (id: number | null | undefined): id is number =>\n  typeof id === 'number' && id > 0","tryCatchPattern":null,"preventionTips":["Always pass the row's id when opening the drawer in edit mode","Disable fetch-models for advanced custom channels until channelId is loaded","Use != null checks so both null and undefined ids trip the guard"],"tags":["state-guard","advanced-custom","fetch-models","channels"],"backgroundTag":null,"analyzedSha":"e2c7aa7b102c2075eae2377df3508658d45e88dc","analyzedAt":"2026-08-15T10:35:18.111Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}