{"record":{"id":"49af3514bcc87c5a","repo":"QuantumNous/new-api","slug":"failed-to-preview-upstream-diff","errorCode":null,"errorMessage":"Failed to preview upstream diff","messagePattern":"Failed to preview upstream diff","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/src/features/models/components/dialogs/sync-wizard-dialog.tsx","lineNumber":86,"sourceCode":"      const preferredSource = SYNC_SOURCE_OPTIONS.find(\n        (option) => option.value === syncWizardOptions.source\n      )\n      setSource(\n        preferredSource && !preferredSource.disabled\n          ? (preferredSource.value as SyncSource)\n          : 'official'\n      )\n    }\n  }, [open, syncWizardOptions, SYNC_SOURCE_OPTIONS])\n\n  const handleSync = async () => {\n    setIsSyncing(true)\n    try {\n      setSyncWizardOptions({ locale, source })\n      const previewRes = await previewUpstreamDiff({ locale, source })\n\n      if (!previewRes.success) {\n        throw new Error(previewRes.message || 'Failed to preview upstream diff')\n      }\n\n      const conflicts = previewRes.data?.conflicts || []\n\n      if (conflicts.length > 0) {\n        toast.warning(\n          `Found ${conflicts.length} conflict${conflicts.length > 1 ? 's' : ''}. Please resolve them first.`\n        )\n        setUpstreamConflicts(conflicts)\n        setOpen('upstream-conflict')\n        return\n      }\n\n      // No conflicts, proceed with sync\n      const response = await syncUpstream({ locale, source })\n\n      if (response.success) {\n        const { created_models, created_vendors, updated_models } =","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/QuantumNous/new-api/blob/e2c7aa7b102c2075eae2377df3508658d45e88dc/web/src/features/models/components/dialogs/sync-wizard-dialog.tsx#L68-L104","documentation":"Thrown by handleSync in the models sync wizard when previewUpstreamDiff({ locale, source }) resolves with success=false. The preview step fetches the diff against the selected upstream source before applying; failure aborts the wizard before conflict handling.","triggerScenarios":"Starting a sync with source 'official' (or another option) where the backend cannot fetch the upstream model listing — GitHub rate limit, upstream repo/mirror unreachable, invalid locale — or the request rejects (session expired).","commonSituations":"Backend has no outbound internet / DNS failure to the upstream host; upstream API rate-limited anonymous requests; locale value not supported; backend version predates the sync endpoint.","solutions":["Retry after a short wait if the upstream rate-limited (common with anonymous GitHub API)","From the backend host, verify reachability of the chosen source endpoint (curl)","Try a different source option in the wizard (e.g. switch mirror) to isolate a dead upstream","Check backend logs for the exact upstream status code returned to previewUpstreamDiff"],"exampleFix":"// before\nconst previewRes = await previewUpstreamDiff({ locale, source })\nif (!previewRes.success) {\n  throw new Error(previewRes.message || 'Failed to preview upstream diff')\n}\n// after - keep the wizard open and show a retryable error state\nconst previewRes = await previewUpstreamDiff({ locale, source })\nif (!previewRes.success) {\n  setSyncError(previewRes.message || 'Failed to preview upstream diff')\n  return\n}","handlingStrategy":"retry","validationCode":"if (!source) { toast.error(t('Select a source first')); return }\nif (!locale) { toast.error(t('Select a locale first')); return }","typeGuard":null,"tryCatchPattern":"setIsSyncing(true)\ntry {\n  const previewRes = await previewUpstreamDiff({ locale, source })\n  if (!previewRes.success) {\n    throw new Error(previewRes.message || 'Failed to preview upstream diff')\n  }\n  const conflicts = previewRes.data?.conflicts || []\n  if (conflicts.length > 0) {\n    setUpstreamConflicts(conflicts)\n    setOpen('upstream-conflict')\n    return\n  }\n} catch (error) {\n  toast.error(error instanceof Error ? error.message : 'Failed to preview upstream diff')\n} finally {\n  setIsSyncing(false)\n}","preventionTips":["Retry once with backoff — upstream rate limits are the most transient cause","Offer a source switcher so a dead mirror does not block the wizard","Keep setIsSyncing(false) in finally so the button re-enables after failure"],"tags":["api-error","sync","models","upstream","wizard"],"backgroundTag":null,"analyzedSha":"e2c7aa7b102c2075eae2377df3508658d45e88dc","analyzedAt":"2026-08-15T10:35:18.111Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}