Dokploy/dokploy · warning · TRPCError
BAD_REQUEST
BAD_REQUEST
Error message
Provide a config or a dnsProviderId to test
What it means
Thrown by `dnsProvider.testConnection` when the mutation is called with neither an inline `config` nor an existing `dnsProviderId`. The procedure needs provider credentials to run a DNS test query, and with both inputs absent there is nothing to test, so it fails fast with BAD_REQUEST before touching any DNS API.
Source
Thrown at apps/dokploy/server/api/routers/dns-provider.ts:111
config: maskDnsProviderConfig(provider.config),
}));
}),
one: withPermission("dnsProvider", "read")
.input(apiFindOneDnsProvider)
.query(async ({ ctx, input }) => {
const provider = await findDnsProviderInOrganization(
input.dnsProviderId,
ctx.session.activeOrganizationId,
);
return { ...provider, config: maskDnsProviderConfig(provider.config) };
}),
testConnection: withPermission("dnsProvider", "create")
.input(apiTestDnsProvider)
.mutation(async ({ ctx, input }) => {
if (!input.config && !input.dnsProviderId) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Provide a config or a dnsProviderId to test",
});
}
let config = input.config;
if (input.dnsProviderId) {
const provider = await findDnsProviderInOrganization(
input.dnsProviderId,
ctx.session.activeOrganizationId,
);
config = config
? mergeDnsProviderConfig(config, provider.config)
: provider.config;
}
await testDnsProviderConnection(config!);
return true;View on GitHub (pinned to 546686ea35)
Solutions
- Pass an inline config (provider, credentials, etc.) when testing unsaved credentials
- Or pass the `dnsProviderId` of a saved provider to test its stored credentials
- Guard the UI: disable the Test button until the form yields a non-empty config or a saved provider is chosen
- Fix clients that send `{}` — log the payload before calling to catch this early
Example fix
// before
await dnsProvider.testConnection.mutate({});
// after
await dnsProvider.testConnection.mutate({
config: { provider: 'cloudflare', cloudflareApiToken: token },
});
// or, for a saved provider:
await dnsProvider.testConnection.mutate({ dnsProviderId }); Defensive patterns
Strategy: validation
Validate before calling
if (!config && !dnsProviderId) {
throw new Error('provide a config or dnsProviderId to test');
}
await dnsProvider.testConnection.mutate(config ? { config } : { dnsProviderId }); Type guard
const hasTestInput = (
i: { config?: unknown; dnsProviderId?: string },
): i is { config: NonNullable<typeof i.config> } | { dnsProviderId: string } =>
Boolean(i.config ?? i.dnsProviderId); Try / catch
try {
await dnsProvider.testConnection.mutate(payload);
} catch (e) {
if (e instanceof TRPCClientError && e.data?.code === 'BAD_REQUEST') {
// populate the form config or select a saved provider, then retry
}
} Prevention
- Disable the Test button until a config or saved provider is selected
- Validate on the client that at least one input is present
- Log outgoing payloads during development to catch empty objects
When it happens
Trigger: Calling `dnsProvider.testConnection` with an empty payload `{}`; passing only whitespace/empty provider fields so `input.config` is falsy while omitting `dnsProviderId`; frontend sending the test request before the form has produced a config object.
Common situations: UI 'Test connection' button enabled before any provider is selected or credentials typed; migration scripts calling the endpoint with a bare object; Zod schema treating an all-optional config as valid (empty object passes validation but fails this runtime check).
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/92656abe3dd12b26.
Report an issue: GitHub.