{"record":{"id":"c7afdd3881807b4c","repo":"Dokploy/dokploy","slug":"failed-to-fetch-models-errortext","errorCode":null,"errorMessage":"Failed to fetch models: ${errorText}","messagePattern":"Failed to fetch models: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/dokploy/server/api/routers/ai.ts","lineNumber":138,"sourceCode":"\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tid: \"MiniMax-M2.7\",\n\t\t\t\t\t\t\t\tobject: \"model\",\n\t\t\t\t\t\t\t\tcreated: Date.now(),\n\t\t\t\t\t\t\t\towned_by: \"minimax\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t] as Model[];\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tif (!input.apiKey)\n\t\t\t\t\t\t\tthrow new TRPCError({\n\t\t\t\t\t\t\t\tcode: \"BAD_REQUEST\",\n\t\t\t\t\t\t\t\tmessage: \"API key must contain at least 1 character(s)\",\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\tresponse = await fetch(`${input.apiUrl}/models`, { headers });\n\t\t\t\t}\n\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tconst errorText = await response.text();\n\t\t\t\t\tthrow new Error(`Failed to fetch models: ${errorText}`);\n\t\t\t\t}\n\n\t\t\t\tconst res = await response.json();\n\n\t\t\t\tif (Array.isArray(res)) {\n\t\t\t\t\treturn res.map((model) => ({\n\t\t\t\t\t\tid: model.id || model.name,\n\t\t\t\t\t\tobject: \"model\",\n\t\t\t\t\t\tcreated: Date.now(),\n\t\t\t\t\t\towned_by: \"provider\",\n\t\t\t\t\t}));\n\t\t\t\t}\n\n\t\t\t\tif (res.models) {\n\t\t\t\t\treturn res.models.map((model: any) => ({\n\t\t\t\t\t\tid: model.id || model.name,\n\t\t\t\t\t\tobject: \"model\",\n\t\t\t\t\t\tcreated: Date.now(),","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/Dokploy/dokploy/blob/546686ea3587f12ec5652217dedd9f7960fb6d15/apps/dokploy/server/api/routers/ai.ts#L120-L156","documentation":"Thrown after a successful Docker removal attempt when the database DELETE on the network table returns no row — i.e. no network row with that networkId exists. NOT_FOUND (not the Docker errors above), and thrown only when .returning() is empty.","triggerScenarios":"Calling removeNetwork twice in a row (second call finds no row); deleting a network whose DB row was already removed; passing a stale or wrong networkId; concurrent deletion racing this call.","commonSituations":"UI retry after a timeout where the first request actually succeeded; duplicated delete buttons firing; state desync between client cache and server.","solutions":["Treat a 404 NOT_FOUND from removeNetwork as idempotent success if the goal is deletion","Refresh the network list in the client after deletion to avoid replaying stale IDs","Guard against double-submission in the UI (disable button while pending)","If it persists, confirm the networkId being sent matches an existing row"],"exampleFix":"// before\nawait api.network.remove.mutate(id);\n// after\ntry {\n  await api.network.remove.mutate(id);\n} catch (e) {\n  if (e?.data?.code === 'NOT_FOUND') return; // already deleted\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"const exists = await db.query.networks.findFirst({\n  where: eq(network.networkId, id),\n});\nif (!exists) return; // nothing to do","typeGuard":null,"tryCatchPattern":"try { await removeNetwork(id); } catch (e) { if (e?.data?.code === 'NOT_FOUND') return; throw e; }","preventionTips":["Make delete calls idempotent by treating NOT_FOUND as success","Disable delete buttons while a request is pending","Refetch the list after every mutation"],"tags":["database","drizzle","trpc","not-found"],"backgroundTag":"resource-not-found","analyzedSha":"546686ea3587f12ec5652217dedd9f7960fb6d15","analyzedAt":"2026-08-27T05:18:58.095Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}