windmill-labs/windmill · error · Error
Error setting flow user state at ${key}: ${e.body}
Error message
Error setting flow user state at ${key}: ${e.body} What it means
setFlowUserState() wraps JobService.setFlowUserState, which writes a key/value into the user state of the root flow job. Any API failure (non-flow context, job not found, permissions, network) is caught and, only if errorIfNotPossible is true, rethrown with this message including the API error body; otherwise it is just logged. The original error object is discarded, so only e.body is visible.
Source
Thrown at typescript-client/client.ts:719
export async function setFlowUserState(
key: string,
value: any,
errorIfNotPossible?: boolean
): Promise<void> {
if (value === undefined) {
value = null;
}
const workspace = getWorkspace();
try {
await JobService.setFlowUserState({
workspace,
id: await getRootJobId(),
key,
requestBody: value,
});
} catch (e: any) {
if (errorIfNotPossible) {
throw Error(`Error setting flow user state at ${key}: ${e.body}`);
} else {
console.error(`Error setting flow user state at ${key}: ${e.body}`);
}
}
}
/**
* Get a flow user state
* @param path path of the variable
*/
export async function getFlowUserState(
key: string,
errorIfNotPossible?: boolean
): Promise<any> {
const workspace = getWorkspace();
try {
return await JobService.getFlowUserState({View on GitHub (pinned to e474e8803c)
Solutions
- Only call setFlowUserState from within a flow execution, or pass errorIfNotPossible=false to tolerate the failure.
- Verify the flow job is still running when the call happens (state can't be set after completion).
- Read the appended e.body in the message — it carries the server's actual reason (404/403/validation).
- Check workspace and token permissions for JobService.setFlowUserState on the root job.
- If thrown persistently due to network, add retry logic around the call.
Example fix
// before (throws and aborts the step)
await setFlowUserState('progress', 42, true);
// after
try {
await setFlowUserState('progress', 42, true);
} catch (e) {
console.error('flow user state unavailable, continuing', e);
} Defensive patterns
Strategy: try-catch
Validate before calling
const rootJobId = getEnv('WM_FLOW_JOB_ID');
if (!rootJobId) {
console.warn('Not in a flow context; setFlowUserState will fail');
} Try / catch
try {
await setFlowUserState(key, value, true);
} catch (e) {
// e.message embeds the API e.body; decide whether the step can proceed without state
console.error(`Could not set flow user state '${key}':`, e.message);
} Prevention
- Call flow user state APIs only from within flow steps, never standalone scripts.
- Omit errorIfNotPossible (or pass false) when state persistence is best-effort.
- Set state while the flow is still running; don't write after completion steps.
- Log and inspect the appended e.body to distinguish 404 (not a flow) from 403 (permissions).
When it happens
Trigger: Calling setFlowUserState(key, value, true) when the code is not running inside a flow (getRootJobId has no root job), the flow job already finished/doesn't exist, the key/value is rejected by the API, or a transient network/auth failure occurs.
Common situations: Using flow user state in a standalone script (not a flow step); writing state after the flow run completed or was cancelled; worker connectivity problems; calling it from tests with a mocked/absent job id.
Understand the failure class
Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.
Related errors
- Variable not found at ${path} or not visible to you: ${e.bod
- Resource at path ${path} does not exist and no type was prov
- Variable not found at ${path} or not visible to you: ${e.bod
- Failed to re-run job ${id}.
- Failed to push completed jobs: ${e}
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/f9ed6c291576250c.
Report an issue: GitHub.