n8n-io/n8n · error · UserError

Workflow "${workflowId}" not found.

Error message

Workflow "${workflowId}" not found.

What it means

UserError thrown by WorkflowRepository.updateActiveState() when no workflow exists with the given workflowId (checked via existsBy). The method flips active/activeVersionId; refusing on a missing workflow prevents writing a phantom update. Distinct from the publishVersion not-found at line 1528.

Source

Thrown at packages/@n8n/db/src/repositories/workflow.repository.ts:1499

	async findIn(workflowIds: string[]) {
		return await this.find({
			select: ['id', 'name'],
			where: { id: In(workflowIds) },
		});
	}

	async findWebhookBasedActiveWorkflows() {
		return await (this.createQueryBuilder('workflow')
			.select('DISTINCT workflow.id, workflow.name')
			.innerJoin(WebhookEntity, 'webhook_entity', 'workflow.id = webhook_entity.workflowId')
			.execute() as Promise<Array<{ id: string; name: string }>>);
	}

	async updateActiveState(workflowId: string, newState: boolean) {
		const wfExists = await this.existsBy({ id: workflowId });
		if (!wfExists) {
			throw new UserError(`Workflow "${workflowId}" not found.`);
		}

		if (newState) {
			return await this.createQueryBuilder()
				.update(WorkflowEntity)
				.set({
					activeVersionId: () => 'versionId',
					active: true,
				})
				.where('id = :workflowId', { workflowId })
				.execute();
		} else {
			return await this.update({ id: workflowId }, { active: false, activeVersionId: null });
		}
	}

	/**
	 * Publish a specific version of a workflow

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Confirm the workflow exists before toggling: `await workflowRepo.existsBy({ id })`.
  2. If the workflow may have been deleted, treat 404 as a normal result and clean up dependent webhooks/triggers.
  3. Validate the ID format upstream (UUID) to fail fast with a clearer message.
  4. For background re-activation jobs, skip rather than throw on missing IDs.

Example fix

// before
await workflowRepo.updateActiveState(workflowId, true);

// after
if (!(await workflowRepo.existsBy({ id: workflowId }))) {
  return { status: 'not_found', workflowId };
}
await workflowRepo.updateActiveState(workflowId, true);
Defensive patterns

Strategy: validation

Validate before calling

if (!(await workflowRepository.existsBy({ id: workflowId }))) {
  // do not call updateActiveState; return not_found
}

Type guard

async function workflowIsActive(id: string): Promise<boolean> {
  return await workflowRepository.existsBy({ id });
}

Try / catch

try {
  await workflowRepository.updateActiveState(workflowId, state);
} catch (err) {
  if (err instanceof UserError && /Workflow .* not found/.test(err.message)) {
    // 404, and clean up dependent webhooks/triggers
  } else throw err;
}

Prevention

When it happens

Trigger: Calling updateActiveState(id, bool) with an id that was deleted, never existed, or is malformed (not a UUID). Common in activation/deactivation flows, webhooks, and the active toggle API.

Common situations: UI 'activate' click racing with a delete; an API call with a stale workflow ID; a webhook re-activation job referencing a removed workflow; copy-paste ID typos; trying to activate an archived workflow via the wrong path.

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/96cd5d66f360f5e4. Report an issue: GitHub.