Dokploy/dokploy · critical · TRPCError

INTERNAL_SERVER_ERROR

INTERNAL_SERVER_ERROR

Error message

Failed to move libsql

What it means

The move-to-environment procedure performs a Drizzle UPDATE ... RETURNING and expects exactly one row back. An empty result (id not matched, concurrent delete, or constraint aborting) triggers INTERNAL_SERVER_ERROR 'Failed to move libsql'.

Source

Thrown at apps/dokploy/server/api/routers/libsql.ts:446

				targetEnvironmentId: z.string(),
			}),
		)
		.mutation(async ({ input, ctx }) => {
			await checkServicePermissionAndAccess(ctx, input.libsqlId, {
				service: ["create"],
			});

			const updatedLibsql = await db
				.update(libsqlTable)
				.set({
					environmentId: input.targetEnvironmentId,
				})
				.where(eq(libsqlTable.libsqlId, input.libsqlId))
				.returning()
				.then((res) => res[0]);

			if (!updatedLibsql) {
				throw new TRPCError({
					code: "INTERNAL_SERVER_ERROR",
					message: "Failed to move libsql",
				});
			}

			await audit(ctx, {
				action: "move",
				resourceType: "service",
				resourceId: updatedLibsql.libsqlId,
				resourceName: updatedLibsql.appName,
			});
			return updatedLibsql;
		}),
	rebuild: protectedProcedure
		.input(apiRebuildLibsql)
		.mutation(async ({ input, ctx }) => {
			await checkServicePermissionAndAccess(ctx, input.libsqlId, {
				deployment: ["create"],

View on GitHub (pinned to 546686ea35)

Solutions

  1. Confirm the libsqlId exists and the target environmentId is valid before moving
  2. Retry after refreshing state — a concurrent delete is the usual culprit
  3. Inspect Postgres logs if it persists; the UPDATE may be failing on a constraint not surfaced by .returning()
Defensive patterns

Strategy: retry

Validate before calling

const [src, dst] = await Promise.all([
  api.libsql.findOne.query({ libsqlId }),
  api.environment.findOne.query({ environmentId }),
]);
if (!src || !dst) throw new Error("verify both ids before moving");

Try / catch

try { await move(); } catch (e) { if (/Failed to move libsql/.test((e as Error).message)) { await refetch(); if (stillExists) retry once; else navigateAway(); } }

Prevention

When it happens

Trigger: Moving a database with a stale/deleted libsqlId, targeting a nonexistent environmentId, or a concurrent delete racing the UPDATE so zero rows return.

Common situations: Drag-and-drop move in the UI racing a deletion; environment removed while a move dialog was open.

Related errors


AI-assisted analysis of Dokploy/dokploy@546686ea35 (2026-08-27). Data as JSON: /api/errors/8310e30bbb846cb7. Report an issue: GitHub.