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
- Archive an existing workspace to free a slot, then retry the fork.
- Pick an existing (non-fork) workspace for the session instead of forking into a new one — clearing the pending workspace unblocks the flow.
- Upgrade to an Enterprise license to lift the workspace limit.
- 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
- Check the workspace count before initiating a fork on CE instances
- Archive unused workspaces proactively
- Pick an existing workspace (clearing the pending fork) instead of forking when near the limit
- Upgrade to EE if multi-workspace forks are a regular workflow
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
- No git-sync repositories configured in workspace
- No workspace available
- No workspace selected
- the session workspace could not be created or committed (for
- trigger kind '${trigger.kind}' requires Enterprise
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/2e642d7a82e16eda.
Report an issue: GitHub.