{"record":{"id":"6ebe75ff8c796ee6","repo":"Dokploy/dokploy","slug":"bad-request-6ebe75","errorCode":"BAD_REQUEST","errorMessage":"Error adding environment variables","messagePattern":"Error adding environment variables","errorType":"exception","errorClass":"TRPCError","httpStatus":400,"severity":"error","filePath":"apps/dokploy/server/api/routers/compose.ts","lineNumber":219,"sourceCode":"\t\t\t\tresourceType: \"compose\",\n\t\t\t\tresourceId: input.composeId,\n\t\t\t\tresourceName: updated?.name,\n\t\t\t});\n\t\t\treturn updated;\n\t\t}),\n\tsaveEnvironment: protectedProcedure\n\t\t.input(apiSaveEnvironmentVariablesCompose)\n\t\t.mutation(async ({ input, ctx }) => {\n\t\t\tawait checkServicePermissionAndAccess(ctx, input.composeId, {\n\t\t\t\tenvVars: [\"write\"],\n\t\t\t});\n\t\t\tconst updated = await updateCompose(input.composeId, {\n\t\t\t\tenv: input.env,\n\t\t\t\tcreateEnvFile: input.createEnvFile,\n\t\t\t});\n\n\t\t\tif (!updated) {\n\t\t\t\tthrow new TRPCError({\n\t\t\t\t\tcode: \"BAD_REQUEST\",\n\t\t\t\t\tmessage: \"Error adding environment variables\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tawait audit(ctx, {\n\t\t\t\taction: \"update\",\n\t\t\t\tresourceType: \"compose\",\n\t\t\t\tresourceId: input.composeId,\n\t\t\t\tresourceName: updated?.name,\n\t\t\t});\n\t\t\treturn true;\n\t\t}),\n\tdelete: protectedProcedure\n\t\t.input(apiDeleteCompose)\n\t\t.mutation(async ({ input, ctx }) => {\n\t\t\tawait checkServiceAccess(ctx, input.composeId, \"delete\");\n\t\t\tconst composeResult = await findComposeById(input.composeId);","sourceCodeStart":201,"sourceCodeEnd":237,"githubUrl":"https://github.com/Dokploy/dokploy/blob/546686ea3587f12ec5652217dedd9f7960fb6d15/apps/dokploy/server/api/routers/compose.ts#L201-L237","documentation":"BAD_REQUEST thrown when updateCompose returns falsy while saving environment variables (env + optional createEnvFile) for a compose. The service returns undefined/null when the update affects no rows — typically because the composeId doesn't exist.","triggerScenarios":"Calling compose.saveEnv (or equivalent) with a deleted/nonexistent composeId, or racing with a concurrent delete so the UPDATE matches zero rows.","commonSituations":"Stale UI after compose deletion, duplicate form submissions around deletion, ID typos in scripts.","solutions":["Confirm the compose still exists (compose.one) before saving env vars","Disable the form during deletion flows; refetch after mutations","Check for concurrent processes deleting the compose"],"exampleFix":"// before\nawait trpc.compose.saveEnv.mutate({ composeId, env, createEnvFile: true });\n\n// after\nconst exists = await trpc.compose.one.query({ composeId });\nif (!exists) throw new Error('Compose no longer exists');\nawait trpc.compose.saveEnv.mutate({ composeId, env, createEnvFile: true });","handlingStrategy":"type-guard","validationCode":"const compose = await trpc.compose.one.query({ composeId }).catch(() => null);\nif (!compose) throw new Error('Compose missing — cannot save env vars');","typeGuard":"async function composeExists(id: string): Promise<boolean> {\n  try { await trpc.compose.one.query({ composeId: id }); return true; }\n  catch { return false; }\n}","tryCatchPattern":"try {\n  await trpc.compose.saveEnv.mutate({ composeId, env });\n} catch (e: any) {\n  if (e.code === 'BAD_REQUEST' && /environment variables/.test(e.message)) {\n    await refreshComposeList(); // likely deleted concurrently\n  }\n}","preventionTips":["Check compose existence before env saves","Lock the UI while delete operations are pending","Refetch after any delete to keep IDs valid"],"tags":["dokploy","trpc","compose","env-vars","no-rows-updated"],"backgroundTag":"update-matched-no-rows","analyzedSha":"546686ea3587f12ec5652217dedd9f7960fb6d15","analyzedAt":"2026-08-27T05:18:58.095Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}