{"record":{"id":"1a18ed853633a819","repo":"payloadcms/payload","slug":"task-with-slug-taskslug-in-workflow-job-workf","errorCode":null,"errorMessage":"Task with slug ${taskSlug} in workflow ${job.workflowSlug} does not have a valid handler.","messagePattern":"Task with slug (.+?) in workflow (.+?) does not have a valid handler\\.","errorType":"exception","errorClass":"TaskError","httpStatus":null,"severity":"error","filePath":"packages/payload/src/queues/operations/runJobs/runJob/getRunTaskFunction.ts","lineNumber":114,"sourceCode":"        } else if (typeof finalRetriesConfig?.shouldRestore === 'function') {\n          shouldRestore = await finalRetriesConfig.shouldRestore({\n            input,\n            job,\n            req,\n            taskStatus,\n          })\n        }\n        if (shouldRestore) {\n          return taskStatus.output\n        }\n      }\n\n      const runner = isInline\n        ? (task as TaskHandler<TaskSlug>)\n        : await getTaskHandlerFromConfig(taskConfig)\n\n      if (!runner || typeof runner !== 'function') {\n        throw new TaskError({\n          executedAt,\n          input,\n          job,\n          message: isInline\n            ? `Inline task with ID ${taskID} does not have a valid handler.`\n            : `Task with slug ${taskSlug} in workflow ${job.workflowSlug} does not have a valid handler.`,\n          parent,\n          retriesConfig: finalRetriesConfig,\n          taskConfig,\n          taskID,\n          taskSlug,\n          taskStatus,\n          workflowConfig,\n        })\n      }\n\n      let output: TaskHandlerResult<string>['output']\n","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/payload/src/queues/operations/runJobs/runJob/getRunTaskFunction.ts#L96-L132","documentation":"Thrown when a configured (non-inline) task's handler cannot be resolved to a function. The runner calls `getTaskHandlerFromConfig(taskConfig)`; if that returns falsy or a non-function, the task has no executable handler — typically because neither a `handler` function nor a resolvable `handler.path` was defined.","triggerScenarios":"A task in `jobs.tasks` / a workflow's tasks has no `handler` and no valid `handler.path`, or the path resolves to a module without a default/named export.","commonSituations":"Defining a task config with only a slug and input/output schema but forgetting the handler; handler path string pointing to a file that has no matching export; refactor removed the handler function.","solutions":["Add `handler: async (args) => {...}` to the task config.","Or set `handler: { path: './tasks/foo.js' }` and ensure that module has a default or named export.","Verify `getTaskHandlerFromConfig` can resolve it by importing the module manually in a test."],"exampleFix":"// before\ntasks: [{ slug: 'resize', inputSchema, /* no handler */ }]\n\n// after\ntasks: [{ slug: 'resize', inputSchema, handler: async ({ input }) => { /* ... */ } }]","handlingStrategy":"validation","validationCode":"import type { TaskConfig } from 'payload'\n\nfunction assertTaskHasHandler(task: TaskConfig): void {\n  const hasFn = typeof task.handler === 'function'\n  const hasPath =\n    !!task.handler && typeof task.handler === 'object' && 'path' in (task.handler as object)\n  if (!hasFn && !hasPath) {\n    throw new Error(`Task \"${task.slug}\" has no handler function or path`)\n  }\n}\n\n(tasks ?? []).forEach(assertTaskHasHandler)","typeGuard":"function hasHandler(task: { handler?: unknown }): boolean {\n  return typeof task.handler === 'function' ||\n    (!!task.handler && typeof task.handler === 'object' && 'path' in (task.handler as object))\n}\n\nif (!hasHandler(taskConfig)) throw new Error('task missing handler')","tryCatchPattern":"try {\n  await runJobs({ req })\n} catch (err) {\n  if (err instanceof Error && err.message.includes('does not have a valid handler')) {\n    // add handler to the task config or fix the handler.path export\n  } else throw err\n}","preventionTips":["Add a config-build test asserting every task has a function or path handler.","When using handler.path, verify the module's default/named export resolves.","Keep handler imports explicit functions rather than paths where possible."],"tags":["jobs","tasks","handler","configuration"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}