{"record":{"id":"cad815574c312bac","repo":"Dokploy/dokploy","slug":"forbidden","errorCode":"FORBIDDEN","errorMessage":"Access denied","messagePattern":"Access denied","errorType":"http","errorClass":"TRPCError","httpStatus":403,"severity":"error","filePath":"apps/dokploy/server/api/routers/ai.ts","lineNumber":247,"sourceCode":"\t\t.input(\n\t\t\tz.object({\n\t\t\t\taiId: z.string().min(1),\n\t\t\t\tlogs: z.string().min(1),\n\t\t\t\tcontext: z.enum([\"build\", \"runtime\"]),\n\t\t\t}),\n\t\t)\n\t\t.mutation(async ({ input, ctx }) => {\n\t\t\ttry {\n\t\t\t\tconst aiSettings = await getAiSettingById(input.aiId);\n\t\t\t\tif (!aiSettings?.isEnabled) {\n\t\t\t\t\tthrow new TRPCError({\n\t\t\t\t\t\tcode: \"BAD_REQUEST\",\n\t\t\t\t\t\tmessage: \"AI provider is not enabled\",\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tif (aiSettings.organizationId !== ctx.session.activeOrganizationId) {\n\t\t\t\t\tthrow new TRPCError({\n\t\t\t\t\t\tcode: \"FORBIDDEN\",\n\t\t\t\t\t\tmessage: \"Access denied\",\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst provider = selectAIProvider(aiSettings);\n\t\t\t\tconst model = provider(aiSettings.model);\n\n\t\t\t\tconst contextLabel =\n\t\t\t\t\tinput.context === \"build\" ? \"build/deployment\" : \"runtime/container\";\n\n\t\t\t\tconst result = await generateText({\n\t\t\t\t\tmodel,\n\t\t\t\t\tprompt: `You are a DevOps engineer analyzing ${contextLabel} logs. Analyze the following logs and provide:\n\n1. **Summary**: A brief summary of what's happening\n2. **Issues Found**: Any errors, warnings, or problems detected\n3. **Root Cause**: The most likely root cause if there are errors","sourceCodeStart":229,"sourceCodeEnd":265,"githubUrl":"https://github.com/Dokploy/dokploy/blob/546686ea3587f12ec5652217dedd9f7960fb6d15/apps/dokploy/server/api/routers/ai.ts#L229-L265","documentation":"Guard inside updateSlackNotification: the UPDATE on the notifications row for input.notificationId returned no row — meaning no notification with that ID exists (or it was deleted), so the update is rejected and the subsequent slack-table update never runs.","triggerScenarios":"Calling updateSlackNotification with a stale, deleted, or mistyped notificationId; concurrent deletion of the destination; updating a notification that belongs to a different resource scope.","commonSituations":"Client caching an old notification list; two admins editing where one deletes; ID copy/paste errors.","solutions":["Refetch the notification list and confirm the ID still exists before editing","Handle BAD_REQUEST here as 'stale ID' and prompt the user to reload","Verify you are passing notificationId (not the slack row ID) — they are different identifiers"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const dest = await db.query.notifications.findFirst({\n  where: eq(notifications.notificationId, input.notificationId),\n});\nif (!dest) throw new Error('Notification no longer exists');","typeGuard":null,"tryCatchPattern":"try { await updateSlackNotification(input); } catch (e) { if (e?.message?.includes('Error Updating')) { /* refetch list and retry */ } throw e; }","preventionTips":["Refetch notifications before editing","Always send notificationId, never the slack row ID"],"tags":["database","drizzle","notification","stale-id"],"backgroundTag":"record-not-found","analyzedSha":"546686ea3587f12ec5652217dedd9f7960fb6d15","analyzedAt":"2026-08-27T05:18:58.095Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}