Dokploy/dokploy · error · TRPCError
BAD_REQUEST
BAD_REQUEST
Error message
Error adding environment variables
What it means
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.
Source
Thrown at apps/dokploy/server/api/routers/compose.ts:219
resourceType: "compose",
resourceId: input.composeId,
resourceName: updated?.name,
});
return updated;
}),
saveEnvironment: protectedProcedure
.input(apiSaveEnvironmentVariablesCompose)
.mutation(async ({ input, ctx }) => {
await checkServicePermissionAndAccess(ctx, input.composeId, {
envVars: ["write"],
});
const updated = await updateCompose(input.composeId, {
env: input.env,
createEnvFile: input.createEnvFile,
});
if (!updated) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Error adding environment variables",
});
}
await audit(ctx, {
action: "update",
resourceType: "compose",
resourceId: input.composeId,
resourceName: updated?.name,
});
return true;
}),
delete: protectedProcedure
.input(apiDeleteCompose)
.mutation(async ({ input, ctx }) => {
await checkServiceAccess(ctx, input.composeId, "delete");
const composeResult = await findComposeById(input.composeId);View on GitHub (pinned to 546686ea35)
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
Example fix
// before
await trpc.compose.saveEnv.mutate({ composeId, env, createEnvFile: true });
// after
const exists = await trpc.compose.one.query({ composeId });
if (!exists) throw new Error('Compose no longer exists');
await trpc.compose.saveEnv.mutate({ composeId, env, createEnvFile: true }); Defensive patterns
Strategy: type-guard
Validate before calling
const compose = await trpc.compose.one.query({ composeId }).catch(() => null);
if (!compose) throw new Error('Compose missing — cannot save env vars'); Type guard
async function composeExists(id: string): Promise<boolean> {
try { await trpc.compose.one.query({ composeId: id }); return true; }
catch { return false; }
} Try / catch
try {
await trpc.compose.saveEnv.mutate({ composeId, env });
} catch (e: any) {
if (e.code === 'BAD_REQUEST' && /environment variables/.test(e.message)) {
await refreshComposeList(); // likely deleted concurrently
}
} Prevention
- Check compose existence before env saves
- Lock the UI while delete operations are pending
- Refetch after any delete to keep IDs valid
When it happens
Trigger: Calling compose.saveEnv (or equivalent) with a deleted/nonexistent composeId, or racing with a concurrent delete so the UPDATE matches zero rows.
Common situations: Stale UI after compose deletion, duplicate form submissions around deletion, ID typos in scripts.
Understand the failure class
Background: BAD_REQUEST error code: request rejected as invalid (HTTP 400) - causes and fixes across libraries — this error's family across 8 libraries.
Related errors
AI-assisted analysis of Dokploy/dokploy@546686ea35 (2026-08-27).
Data as JSON: /api/errors/6ebe75ff8c796ee6.
Report an issue: GitHub.