Dokploy/dokploy · error · TRPCError
INTERNAL_SERVER_ERROR
INTERNAL_SERVER_ERROR
Error message
Failed to move compose
What it means
Thrown by the moveCompose tRPC mutation when the Drizzle update()...returning() query for composeTable does not return a row. Returning() normally fails loudly; an empty result means the WHERE clause (composeId) matched no row after the update executed.
Source
Thrown at apps/dokploy/server/api/routers/compose.ts:790
targetEnvironmentId: z.string(),
}),
)
.mutation(async ({ input, ctx }) => {
await checkServicePermissionAndAccess(ctx, input.composeId, {
service: ["create"],
});
const updatedCompose = await db
.update(composeTable)
.set({
environmentId: input.targetEnvironmentId,
})
.where(eq(composeTable.composeId, input.composeId))
.returning()
.then((res) => res[0]);
if (!updatedCompose) {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Failed to move compose",
});
}
await audit(ctx, {
action: "update",
resourceType: "compose",
resourceId: input.composeId,
resourceName: updatedCompose.name,
});
return updatedCompose;
}),
processTemplate: protectedProcedure
.input(
z.object({
base64: z.string(),View on GitHub (pinned to 546686ea35)
Solutions
- Verify the composeId exists (findComposeById) before calling moveCompose
- Refresh the client state/refetch composes after deletions
- Wrap the call and treat empty result as NOT_FOUND rather than retrying
Example fix
// before
await api.compose.moveCompose({ composeId, serverId });
// after
const compose = await api.compose.get.byComposeId({ composeId });
if (!compose) throw new Error('Compose no longer exists');
await api.compose.moveCompose({ composeId, serverId }); Defensive patterns
Strategy: validation
Validate before calling
const compose = await findComposeById(composeId);
if (!compose) throw new Error('Compose not found'); Prevention
- Refetch compose list after delete operations
- Pass fresh IDs from current query results
When it happens
Trigger: Calling moveCompose with a composeId that does not exist in the compose table, or that was concurrently deleted between authorization and the update.
Common situations: Stale UI holding a deleted compose's ID; race with a simultaneous delete; passing an ID from a different environment/database.
Related errors
- Failed to fetch models: ${errorText}
- FORBIDDEN
- No response received from the model
- UNAUTHORIZED
- UNAUTHORIZED
AI-assisted analysis of Dokploy/dokploy@546686ea35 (2026-08-27).
Data as JSON: /api/errors/0fe7600d08236c45.
Report an issue: GitHub.