{"record":{"id":"525a72aebd94a21b","repo":"nocobase/nocobase","slug":"job-of-head-node-node-id-not-found-in-execut","errorCode":null,"errorMessage":"job of head node (#${node.id}) not found in execution (#${this.execution.id})","messagePattern":"job of head node \\(#(.+?)\\) not found in execution \\(#(.+?)\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/plugins/@nocobase/plugin-workflow/src/server/Processor.ts","lineNumber":341,"sourceCode":"    try {\n      await this.prepare();\n      const node: FlowNodeModel = this.nodesMap.get(job.nodeId) as FlowNodeModel;\n      await this.recall(node, job);\n    } finally {\n      this.leaveRunningState();\n    }\n  }\n\n  private resolveRerun(options: ProcessorRerunOptions = {}) {\n    const node = this.getRerunNode(options.nodeId);\n    const targetJob = this.jobsMapByNodeKey[node.key];\n\n    if (options.nodeId != null && !targetJob) {\n      throw new Error(`job of node (#${node.id}) not found in execution (#${this.execution.id})`);\n    }\n\n    if (options.nodeId == null && options.overwrite && !targetJob) {\n      throw new Error(`job of head node (#${node.id}) not found in execution (#${this.execution.id})`);\n    }\n\n    const input = this.getRerunInput(node);\n    return { node, input, targetJob };\n  }\n\n  public async rerun(options: ProcessorRerunOptions = {}) {\n    const { execution } = this;\n    if (execution.status !== EXECUTION_STATUS.STARTED) {\n      throw new Error(`execution (#${execution.id}) is not started`);\n    }\n    if (!(await this.shouldContinueExecution())) {\n      this.logger.warn(`execution was ended with status ${execution.status} before, could not be rerun`, {\n        workflowId: execution.workflowId,\n      });\n      return;\n    }\n","sourceCodeStart":323,"sourceCodeEnd":359,"githubUrl":"https://github.com/nocobase/nocobase/blob/fa42722fefe44265490dff2c27d79e2882bce4fa/packages/plugins/@nocobase/plugin-workflow/src/server/Processor.ts#L323-L359","documentation":"This is the head-node variant of the rerun check: when rerun is called without nodeId but with overwrite=true, resolveRerun requires an existing job for the workflow's head node, because overwriting a rerun must replace an existing prior result. If the head node has no job recorded, it throws.","triggerScenarios":"processor.rerun({ overwrite: true }) on an execution whose head node never produced a job — e.g. the execution started but failed before the head node executed, jobs were deleted, or the first node's key changed so jobsMapByNodeKey lookup misses.","commonSituations":"Overwrite-rerun of a freshly created execution that has not executed any node yet; rerun after job cleanup jobs purged the head job; workflow edited so the current head node differs from the one that ran.","solutions":["Wait until the execution has at least run its head node before calling rerun with overwrite: true.","Call rerun() without overwrite (append mode) if you don't need to replace prior results.","If jobs were purged, re-trigger the workflow to create a new execution instead of rerunning.","Confirm the head node (node without upstream) matches the node that produced the job."],"exampleFix":"// before\nawait processor.rerun({ overwrite: true }); // throws if nothing ran yet\n// after\nconst head = execution.workflow.nodes.find((n) => !n.upstream);\nconst hasJob = await execution.countJobs({ where: { nodeId: head.id } });\nawait processor.rerun({ overwrite: hasJob > 0 });","handlingStrategy":"validation","validationCode":"const head = workflow.nodes.find((n) => !n.upstream);\nconst headJob = head && (await execution.countJobs({ where: { nodeId: head.id } }));\nif (overwrite && !headJob) {\n  throw new Error('cannot overwrite-rerun: head node has not executed in this execution yet');\n}","typeGuard":"function canOverwriteRerun(execution: ExecutionModel, workflow: WorkflowModel): boolean {\n  const head = (workflow.nodes ?? []).find((n) => !n.upstream);\n  return !!head && Array.isArray(execution.jobs) && execution.jobs.some((j) => j.nodeId === head.id);\n}","tryCatchPattern":"try {\n  await processor.rerun({ overwrite: true });\n} catch (e) {\n  if (/job of head node/.test(e.message)) {\n    logger.warn('nothing executed yet; running append-mode rerun instead');\n    await processor.rerun({});\n    return;\n  }\n  throw e;\n}","preventionTips":["Use overwrite: true only on executions with prior successful node runs.","Debounce/deduplicate rerun button clicks so a completed rerun isn't re-invoked.","Check execution status and job count before choosing overwrite mode.","Avoid editing the workflow head node while executions are pending rerun."],"tags":["workflow","rerun","execution"],"backgroundTag":"rerun-job-not-found","analyzedSha":"fa42722fefe44265490dff2c27d79e2882bce4fa","analyzedAt":"2026-09-01T00:54:31.202Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}