Dokploy/dokploy · error · TRPCError

BAD_REQUEST

BAD_REQUEST

Error message

error instanceof Error ? error.message : "Error creating the domain"

What it means

The create-domain procedure in Dokploy wraps its main body in a try/catch: any error thrown while creating a domain (unique-constraint violation, invalid host, certificate or traefik config failure) is rethrown as TRPCError BAD_REQUEST, using the original error's message when available and 'Error creating the domain' otherwise. So the message you see is a passthrough of the underlying cause; inspect error.cause for the real error.

Source

Thrown at apps/dokploy/server/api/routers/domain.ts:57

				if (input.domainType === "compose" && input.composeId) {
					await checkServicePermissionAndAccess(ctx, input.composeId, {
						domain: ["create"],
					});
				} else if (input.domainType === "application" && input.applicationId) {
					await checkServicePermissionAndAccess(ctx, input.applicationId, {
						domain: ["create"],
					});
				}
				const domain = await createDomain(input);
				await audit(ctx, {
					action: "create",
					resourceType: "domain",
					resourceId: domain.domainId,
					resourceName: domain.host,
				});
				return domain;
			} catch (error) {
				throw new TRPCError({
					code: "BAD_REQUEST",
					message:
						error instanceof Error
							? error.message
							: "Error creating the domain",
					cause: error,
				});
			}
		}),
	byApplicationId: protectedProcedure
		.input(apiFindOneApplication)
		.query(async ({ input, ctx }) => {
			await checkServicePermissionAndAccess(ctx, input.applicationId, {
				domain: ["read"],
			});
			return await findDomainsByApplicationId(input.applicationId);
		}),
	byComposeId: protectedProcedure

View on GitHub (pinned to 546686ea35)

Solutions

  1. Read error.cause (or server logs) to identify the underlying failure — the TRPC message is often the DB/driver message
  2. Check for an existing domain with the same host and remove/reuse it before creating again
  3. Validate host format (FQDN, optional wildcard) before submitting
  4. If a partial record was left behind, clean it up and retry

Example fix

// before
await trpc.domain.create.mutate({ host: 'app.example.com', ... });

// after
const existing = (await trpc.domain.byAppId.query({ appId })).find(
  (d) => d.host === 'app.example.com',
);
if (existing) throw new Error('Host already used by this app');
await trpc.domain.create.mutate({ host: 'app.example.com', ... });
Defensive patterns

Strategy: validation

Validate before calling

const existing = (await trpc.domain.byAppId.query({ appId }))
  .find((d) => d.host === input.host);
if (existing) throw new Error('Host already exists for this app');

Type guard

const isValidHost = (h: string) =>
  /^^(?:\\*\\.)?(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z]{2,}$/.test(h);

Try / catch

try {
  await trpc.domain.create.mutate(input);
} catch (e) {
  if (e instanceof TRPCClientError && e.data?.code === 'BAD_REQUEST') {
    console.error('Domain create failed:', e.message, e.shape?.data?.cause);
  }
}

Prevention

When it happens

Trigger: docker.../domain.create mutation failing downstream — most commonly creating a domain whose host already exists for the application (unique constraint), a malformed host, or missing required fields surfaced by the domain creation service.

Common situations: Duplicate hostnames across apps; typo'd wildcard hosts; SQLite/Postgres unique index violations from prior partial inserts; traefik/certifier config errors during domain provisioning.

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/77a006b618f7f221. Report an issue: GitHub.