windmill-labs/windmill · error

Cannot set value on objects that are neither the global stat

Error message

Cannot set value on objects that are neither the global state or a container group field

What it means

In Windmill app frontend expressions, the eval sandbox wraps context objects in a Proxy whose set trap only allows writes to the global 'state' object (or to a container 'group' field when a group context exists). Writing to any other proxied object (e.g. results, inputs, UI component outputs) throws this error. It exists because only state mutations are tracked and allowed to trigger recomputes.

Source

Thrown at frontend/src/lib/components/apps/components/helpers/eval.ts:146

			setGroupValue?: (key: string, value: any) => void
			sendMessage?: (message: string) => void
		}
	>,
	worldStore: World | undefined,
	runnableComponents: Record<string, { cb?: (() => void)[] }>,
	noReturn: boolean,
	groupContextId: string | undefined,
	globalRecomputeFunction: ((excludeIds?: string) => void) | undefined
) {
	const createProxy = (name: string, obj: any) => {
		// console.log('Creating proxy', name, obj)
		if (obj != null && obj != undefined && typeof obj == 'object') {
			if (name == 'group' && groupContextId) {
				return createGroupProxy(groupContextId, obj)
			}
			return new Proxy(obj, {
				set(target, key, value) {
					if (name != 'state') {
						throw new Error(
							'Cannot set value on objects that are neither the global state or a container group field'
						)
					}
					if (typeof key !== 'string') {
						throw new Error('Invalid key')
					}
					target[key] = value
					let o = worldStore?.newOutput(name, key, value)
					o?.set(value, true)

					return true
				},
				get(obj, prop) {
					if (name != 'state' && prop == 'group') {
						return createGroupProxy(name, obj[prop])
					} else {
						return obj[prop]

View on GitHub (pinned to e474e8803c)

Solutions

  1. Assign to the global state instead: `state.myKey = value`, then reference state.myKey elsewhere
  2. If inside a container component, write via the group proxy: `group.myKey = value` (only valid within a container group context)
  3. To mutate a component programmatically, use its control API (e.g. controlComponents setValue/setTab) rather than assigning to the result object
  4. For persisted values across runs, use a state variable or a resource, not step results

Example fix

// before (onClick handler)
results.total = inputs.a + inputs.b
// after
state.total = inputs.a + inputs.b
Defensive patterns

Strategy: try-catch

Validate before calling

// before writing in an app expression, ensure the target is state (or group inside a container)
if (targetName !== 'state') {
  // redirect the write to state instead
  state[myKey] = value
}

Try / catch

try {
  results.total = inputs.a + inputs.b
} catch (e) {
  if (String(e.message).includes('neither the global state')) {
    state.total = inputs.a + inputs.b // fall back to the sanctioned target
  } else throw e
}

Prevention

When it happens

Trigger: Inside an app frontend expression/event handler, assigning to a non-state context object, e.g. `results.myStep = ...`, `inputs.x = 1`, `ui.button.disabled = true` at top level, or `myComponent.someProp = v` when the component is not exposed as a container group field with a groupContextId.

Common situations: Trying to save computed data back onto step results instead of state; mutating a component's returned object from a button onClick handler; copy-pasting `results.foo = bar` patterns from scripts into app expressions; group writes attempted without a container group context (groupContextId undefined).

Related errors


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