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: protectedProcedureView on GitHub (pinned to 546686ea35)
Solutions
- Read error.cause (or server logs) to identify the underlying failure — the TRPC message is often the DB/driver message
- Check for an existing domain with the same host and remove/reuse it before creating again
- Validate host format (FQDN, optional wildcard) before submitting
- 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
- Check host uniqueness per app before creating
- Inspect error.cause for the real underlying failure
- Validate host format client-side before submitting
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.