windmill-labs/windmill · error · Error
This function can only be called as a flow step
Error message
This function can only be called as a flow step
What it means
windmill's TypeScript client throws this when an approval-related helper in client.ts is invoked without the WM_FLOW_STEP_ID environment variable set. The function works only as a step inside a running flow, where Windmill injects that variable to identify the current step. Outside a flow (standalone script, preview) there is no step to attach the approval to, so the call cannot proceed.
Source
Thrown at typescript-client/client.ts:1361
message,
approver,
defaultArgsJson,
dynamicEnumsJson,
resumeButtonText,
cancelButtonText,
}: SlackApprovalOptions): Promise<void> {
const workspace = getWorkspace();
const flowJobId = getEnv("WM_FLOW_JOB_ID");
if (!flowJobId) {
throw new Error(
"You can't use this function in a standalone script or flow step preview. Please use it in a flow or a flow preview."
);
}
const flowStepId = getEnv("WM_FLOW_STEP_ID");
if (!flowStepId) {
throw new Error("This function can only be called as a flow step");
}
// Only include non-empty parameters
const params: {
approver?: string;
message?: string;
slackResourcePath: string;
channelId: string;
flowStepId: string;
defaultArgsJson?: string;
dynamicEnumsJson?: string;
resumeButtonText?: string;
cancelButtonText?: string;
} = {
slackResourcePath,
channelId,
flowStepId,
};View on GitHub (pinned to e474e8803c)
Solutions
- Run the code as a step inside a flow (add the script to a flow in the Windmill UI) so WM_FLOW_STEP_ID is injected.
- If testing, guard the call: `if (!getEnv("WM_FLOW_STEP_ID")) return;` or stub the env for the test.
- Use the flow preview mode of the Windmill UI for development instead of executing the script standalone.
- Verify your worker/runner does not sanitize the environment and remove WM_FLOW_STEP_ID.
Example fix
// before
await teamsApproval({ approver: 'admin@corp.com', message: 'ok' }); // standalone -> throws
// after
if (getEnv('WM_FLOW_STEP_ID')) {
await teamsApproval({ approver: 'admin@corp.com', message: 'ok' });
} else {
console.log('skipped: not running as a flow step');
} Defensive patterns
Strategy: validation
Validate before calling
import { getEnv } from 'windmill-client';
export const isFlowStep = () => Boolean(getEnv('WM_FLOW_STEP_ID')); Type guard
function requireFlowStepId(): string {
const id = getEnv('WM_FLOW_STEP_ID');
if (!id) throw new Error('not running as a flow step');
return id;
} Try / catch
try {
await approvalFn(opts);
} catch (e) {
if (e.message === 'This function can only be called as a flow step') {
// skip or fallback in standalone runs
} else throw e;
} Prevention
- Only call approval helpers from flow steps, never standalone scripts.
- Guard calls with a WM_FLOW_STEP_ID check in shared code.
- Use flow preview only for logic that does not call these APIs.
When it happens
Trigger: Calling the approval function (typescript-client/client.ts:1361) from a standalone script run, a CLI execution, or any environment where getEnv("WM_FLOW_STEP_ID") returns empty.
Common situations: Testing approval code locally with `wmill script run` or `deno run`; running the script as a top-level script instead of a flow step; sandboxed or custom-runner environments that strip Windmill-injected env vars.
Related errors
- You can't use this function in a standalone script or flow s
- You can't use 'request_interactive_slack_approval' function
- WAC step key "{requested_key}" is already used in this workf
- resume request already sent
- the flow is not in a suspended state anymore
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/7c038dba935ccb44.
Report an issue: GitHub.