{"record":{"id":"8ec970bae5e29b0d","repo":"windmill-labs/windmill","slug":"taskscript-path-can-only-be-called-inside-a","errorCode":null,"errorMessage":"taskScript(\"${path}\") can only be called inside a workflow()","messagePattern":"taskScript\\(\"(.+?)\"\\) can only be called inside a workflow\\(\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"typescript-client/client.ts","lineNumber":2267,"sourceCode":"\n/**\n * Create a task that dispatches to a separate Windmill script.\n *\n * @example\n * const extract = taskScript(\"f/data/extract\");\n * // inside workflow: await extract({ url: \"https://...\" })\n */\nexport function taskScript(path: string, options?: TaskOptions): (...args: any[]) => PromiseLike<any> {\n  const name = path.split(\"/\").pop() || path;\n  const wrapper = function (...args: any[]) {\n    const ctx: WorkflowCtx | null = _workflowCtx ?? Reflect.get(globalThis, \"__wmill_wf_ctx\");\n    if (ctx) {\n      const kwargs = args.length === 1 && typeof args[0] === \"object\" && args[0] !== null\n        ? args[0]\n        : args.reduce((acc, v, i) => { acc[`arg${i}`] = v; return acc; }, {} as Record<string, any>);\n      return ctx._nextStep(name, path, kwargs, \"script\", options);\n    }\n    throw new Error(`taskScript(\"${path}\") can only be called inside a workflow()`);\n  };\n  Object.defineProperty(wrapper, \"name\", { value: name });\n  (wrapper as any)._is_task = true;\n  (wrapper as any)._task_path = path;\n  return wrapper;\n}\n\n/**\n * Create a task that dispatches to a separate Windmill flow.\n *\n * @example\n * const pipeline = taskFlow(\"f/etl/pipeline\");\n * // inside workflow: await pipeline({ input: data })\n */\nexport function taskFlow(path: string, options?: TaskOptions): (...args: any[]) => PromiseLike<any> {\n  const name = path.split(\"/\").pop() || path;\n  const wrapper = function (...args: any[]) {\n    const ctx: WorkflowCtx | null = _workflowCtx ?? Reflect.get(globalThis, \"__wmill_wf_ctx\");","sourceCodeStart":2249,"sourceCodeEnd":2285,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/typescript-client/client.ts#L2249-L2285","documentation":"taskScript(path) is a step-composition helper that must run under an active workflow() context: it delegates to ctx._nextStep to append a script step to the workflow being built. When no workflow context is registered, the wrapper throws this error naming the path (typescript-client/client.ts:2267), because a script task outside workflow() has nothing to be scheduled onto.","triggerScenarios":"Calling a taskScript-created function at module top level, inside a plain main(), or after the workflow() callback returned; context not propagated into async callbacks or nested closures.","commonSituations":"Calling the task in unit tests without a workflow harness; awaiting the task outside the workflow callback; refactoring moved the call out of workflow() scope; the global ctx unset because multiple client bundles were loaded.","solutions":["Move the taskScript call inside the workflow() callback so the context is active.","If calling from a helper, keep the helper synchronous within the workflow callback scope.","For tests, use a harness/stub that installs a workflow context (setWorkflowCtx).","Check that an earlier await did not detach the call from the active workflow context."],"exampleFix":"// before\nexport async function main() {\n  await greet('world'); // taskScript outside workflow() -> throws\n}\n// after\nexport async function main() {\n  await workflow(async () => {\n    await greet('world'); // inside workflow context\n  });\n}","handlingStrategy":"try-catch","validationCode":"const inWorkflow = () =>\n  Boolean(_workflowCtx ?? Reflect.get(globalThis, '__wmill_wf_ctx'));","typeGuard":"function requireWorkflowCtx(): WorkflowCtx {\n  const ctx: WorkflowCtx | null = _workflowCtx ?? Reflect.get(globalThis, '__wmill_wf_ctx');\n  if (!ctx) throw new Error('taskScript called outside workflow()');\n  return ctx;\n}","tryCatchPattern":"try {\n  await greet('world');\n} catch (e) {\n  if (e.message.includes('can only be called inside a workflow()')) {\n    // fall back to direct execution for standalone runs\n    await windmill.runScript('u/greet', { args: ['world'] });\n  } else throw e;\n}","preventionTips":["Always invoke task functions inside the workflow() callback.","Use a workflow test harness/stub context for unit tests.","Avoid fire-and-forget or detached awaits around task calls.","Keep one bundled copy of the client so the context global matches."],"tags":["workflow","task","context"],"backgroundTag":"function-requires-workflow-context","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}