Dokploy/dokploy · error · TRPCError

UNAUTHORIZED

UNAUTHORIZED

Error message

You need to use a server to create a compose

What it means

Thrown by `compose.create`: in Dokploy Cloud (IS_CLOUD) or when the self-hosted instance has remoteServersOnly enabled in web server settings, a compose must be attached to an explicit serverId — there is no default local server to deploy to.

Source

Thrown at apps/dokploy/server/api/routers/compose.ts:98

import { createTRPCRouter, protectedProcedure } from "../trpc";
import { audit } from "../utils/audit";

export const composeRouter = createTRPCRouter({
	create: protectedProcedure
		.input(apiCreateCompose)
		.mutation(async ({ ctx, input }) => {
			try {
				const environment = await findEnvironmentById(input.environmentId);
				const project = await findProjectById(environment.projectId);

				await checkServiceAccess(ctx, project.projectId, "create");

				const webServerSettings = await getWebServerSettings();
				if (
					(IS_CLOUD || webServerSettings?.remoteServersOnly) &&
					!input.serverId
				) {
					throw new TRPCError({
						code: "UNAUTHORIZED",
						message: "You need to use a server to create a compose",
					});
				}
				if (project.organizationId !== ctx.session.activeOrganizationId) {
					throw new TRPCError({
						code: "UNAUTHORIZED",
						message: "You are not authorized to access this project",
					});
				}

				if (input.serverId) {
					const accessibleIds = await getAccessibleServerIds(ctx.session);
					if (!accessibleIds.has(input.serverId)) {
						throw new TRPCError({
							code: "UNAUTHORIZED",
							message: "You are not authorized to access this server",
						});

View on GitHub (pinned to 546686ea35)

Solutions

  1. Pass a serverId owned by your organization in the compose create input
  2. If self-hosted and you want local deployment, disable remoteServersOnly in the web server settings
  3. Pick a default server in the UI before creating the compose

Example fix

// before
await trpc.compose.create.mutate({ name: 'api', projectId, ... });

// after
await trpc.compose.create.mutate({ name: 'api', projectId, serverId: 'srv_xxx', ... });
Defensive patterns

Strategy: validation

Validate before calling

const servers = await trpc.server.all.query();
if (!servers.length) throw new Error('Create/attach a server before adding composes');
input.serverId ??= servers[0].serverId;

Type guard

function hasServerId<T extends { serverId?: string }>(i: T): i is T & { serverId: string } {
  return typeof i.serverId === 'string' && i.serverId.length > 0;
}

Prevention

When it happens

Trigger: Calling compose.create without input.serverId while IS_CLOUD=true or admin settings set remoteServersOnly.

Common situations: Custom scripts or older clients built before the remote-servers-only setting; admin enabling remoteServersOnly and existing UI flows not yet supplying a server; using the cloud version with a self-hosted-style payload.

Related errors


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