n8n-io/n8n · error · UserError

Version "${versionIdToPublish}" not found for workflow "${wo

Error message

Version "${versionIdToPublish}" not found for workflow "${workflowId}".

What it means

UserError thrown by WorkflowRepository.publishVersion() when the workflow exists and isn't archived, but the requested versionId (or the workflow's current versionId when none is supplied) has no matching row in workflowHistoryRepository. Means the version to publish isn't in history — either deleted, never saved, or mismatched.

Source

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

		if (!workflow) {
			throw new UserError(`Workflow "${workflowId}" not found.`);
		}

		if (workflow.isArchived) {
			throw new UserError('Cannot publish archived Workflow', {
				extra: { workflowId },
			});
		}

		const versionIdToPublish = versionId ?? workflow.versionId;

		const version = await this.workflowHistoryRepository.findOneBy({
			workflowId,
			versionId: versionIdToPublish,
		});
		if (!version) {
			throw new UserError(
				`Version "${versionIdToPublish}" not found for workflow "${workflowId}".`,
			);
		}

		return await this.update(
			{ id: workflowId },
			{ active: true, activeVersionId: versionIdToPublish },
		);
	}

	async unpublishAll() {
		return await this.update(
			{ activeVersionId: Not(IsNull()) },
			{ active: false, activeVersionId: null },
		);
	}

	async findByActiveState(activeState: boolean) {

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. List available versions before publishing: `await workflowHistoryRepo.find({ where: { workflowId } })` and validate the chosen versionId.
  2. Increase history retention if versions are being pruned too aggressively.
  3. If publishing the current version, ensure workflow.versionId corresponds to an existing history row; re-save the workflow to materialize one if needed.
  4. Never accept arbitrary version IDs from untrusted input without an existence check.

Example fix

// before
await workflowRepo.publishVersion(workflowId, requestedVersionId);

// after
const version = await workflowHistoryRepository.findOneBy({
  workflowId,
  versionId: requestedVersionId,
});
if (!version) throw new UserError(`Version '${requestedVersionId}' not in history for workflow '${workflowId}'`);
await workflowRepo.publishVersion(workflowId, requestedVersionId);
Defensive patterns

Strategy: validation

Validate before calling

const version = await workflowHistoryRepository.findOneBy({ workflowId, versionId: requestedVersionId });
if (!version) { // do not call publishVersion; surface 'version not in history' }

Type guard

async function versionInHistory(workflowId: string, versionId: string): Promise<boolean> {
  return Boolean(await workflowHistoryRepository.existsBy({ workflowId, versionId }));
}

Try / catch

try {
  await workflowRepository.publishVersion(workflowId, versionId);
} catch (err) {
  if (err instanceof UserError && /Version .* not found for workflow/.test(err.message)) {
    // list available versions and ask user to pick a valid one
  } else throw err;
}

Prevention

When it happens

Trigger: Calling publishVersion(workflowId, versionId) where versionId doesn't exist for that workflow; or omitting versionId when workflow.versionId itself is stale/missing from history. The findOneBy on (workflowId, versionIdToPublish) returns null.

Common situations: History retention purged old versions; a version ID copied from a different workflow; race where the version was pruned between read and publish; manual DB surgery that removed history rows; the workflow's current versionId predates history tracking.

Related errors


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