windmill-labs/windmill · error

Community edition is limited to ${CE_MAX_NON_ADMIN_WORKSPACE

Error message

Community edition is limited to ${CE_MAX_NON_ADMIN_WORKSPACES + 1} workspaces — archive a workspace or pick one to run in

What it means

sessionState.svelte.ts enforces the Community Edition limit of 2 non-admin workspaces (CE_MAX_NON_ADMIN_WORKSPACES = 2, +1 counting the admins workspace). When materializing a session fork would create a workspace beyond that limit on a non-EE instance, this error is thrown before materializeFork is called. The pending fork is intentionally kept set so the block persists until the user picks a non-fork workspace (setSessionPendingWorkspace clears it).

Source

Thrown at frontend/src/lib/components/sessions/sessionState.svelte.ts:913

	if (s.workspace_id) return s.workspace_id
	// A commit is a send: the record must be durable regardless of prior touches
	// (a draft sent without ever being touched is still transient here).
	if (s.transient) delete s.transient

	if (s.pending_fork) {
		const fork = s.pending_fork
		// Defense-in-depth against a stale pending_fork (e.g. staged before
		// another workspace was created, or any future entry point): a fork is a
		// new workspace, and community edition caps the number of non-'admins'
		// workspaces (backend _check_nb_of_workspaces). An enterprise license
		// lifts the cap. Block the commit with an explicit error rather than
		// letting materializeFork hit a backend rejection. Keep the pending fork
		// set so the block persists until the user picks a non-fork workspace
		// (setSessionPendingWorkspace clears it).
		const CE_MAX_NON_ADMIN_WORKSPACES = 2
		const nonAdminWorkspaceCount = get(userWorkspaces).filter((w) => w.id !== 'admins').length
		if (!get(enterpriseLicense) && nonAdminWorkspaceCount >= CE_MAX_NON_ADMIN_WORKSPACES) {
			throw new Error(
				`Community edition is limited to ${CE_MAX_NON_ADMIN_WORKSPACES + 1} workspaces — archive a workspace or pick one to run in`
			)
		}
		const newId = await materializeFork(fork)
		if (!newId) {
			// Real failure (not a recovered duplicate). Drop the pending
			// fork so the session falls through to the workspace-pick
			// fallback on the next call and the unavailable-banner UX
			// can take over instead of looping on the same broken intent.
			s.pending_fork = undefined
			void putSession(s)
			return undefined
		}
		s.workspace_id = newId
		s.pending_fork = undefined
		s.pending_workspace_id = undefined
		s.workspace_root_id = workspaceRootId(newId, get(userWorkspaces)) ?? newId
		// The draft prompt has been consumed as the first message.

View on GitHub (pinned to e474e8803c)

Solutions

  1. Archive an existing workspace to free a slot, then retry the fork.
  2. Pick an existing (non-fork) workspace for the session instead of forking into a new one — clearing the pending workspace unblocks the flow.
  3. Upgrade to an Enterprise license to lift the workspace limit.
  4. For local/dev testing, remove or archive unused non-admin workspaces before forking.

Example fix

// before
const newId = await materializeFork(fork) // throws on CE limit
// after
const canFork = get(enterpriseLicense) ||
  get(userWorkspaces).filter((w) => w.id !== 'admins').length < CE_MAX_NON_ADMIN_WORKSPACES
if (canFork) {
  const newId = await materializeFork(fork)
} else {
  // prompt the user to pick an existing workspace or archive one
}
Defensive patterns

Strategy: validation

Validate before calling

import { get } from 'svelte/store'
import { userWorkspaces, enterpriseLicense } from '$lib/stores'
function canCreateWorkspace(): boolean {
  if (get(enterpriseLicense)) return true
  return get(userWorkspaces).filter((w) => w.id !== 'admins').length < 2
}

Type guard

function hasEnterpriseLicense(v: unknown): v is EnterpriseLicense {
  return v !== null && v !== undefined
}

Try / catch

try {
  const id = await materializeFork(fork)
} catch (e) {
  if (String(e).includes('Community edition is limited')) {
    toast.error('CE workspace limit reached — archive a workspace or pick an existing one')
    // keep pending fork set so the block persists by design
    return
  }
  throw e
}

Prevention

When it happens

Trigger: On a Community Edition instance (no enterpriseLicense), attempting to create/commit a session fork when `get(userWorkspaces)` already contains CE_MAX_NON_ADMIN_WORKSPACES (2) workspaces other than 'admins'.

Common situations: Running the free CE edition in a setup with several workspaces and trying to fork a session into a new workspace; hitting this during AI session runs that auto-fork.

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/2e642d7a82e16eda. Report an issue: GitHub.