langgenius/dify · warning · NotFound

last run not found

Error message

last run not found

What it means

Raised as NotFound("last run not found") (HTTP 404) in RagPipelineWorkflowLastRunApi.get after the draft workflow is found but get_node_last_run returns None. It means the node exists in the draft context but has never produced an execution record, so there is no 'last run' to return.

Source

Thrown at api/controllers/console/datasets/rag_pipeline/rag_pipeline_workflow.py:1012

        "Node last run retrieved successfully",
        console_ns.models[WorkflowRunNodeExecutionResponse.__name__],
    )
    @setup_required
    @login_required
    @account_initialization_required
    @get_rag_pipeline
    def get(self, pipeline: Pipeline, node_id: str):
        rag_pipeline_service = RagPipelineService(db.session())
        workflow = rag_pipeline_service.get_draft_workflow(pipeline=pipeline)
        if not workflow:
            raise NotFound("Workflow not found")
        node_exec = rag_pipeline_service.get_node_last_run(
            pipeline=pipeline,
            workflow=workflow,
            node_id=node_id,
        )
        if node_exec is None:
            raise NotFound("last run not found")
        return WorkflowRunNodeExecutionResponse.model_validate(node_exec, from_attributes=True).model_dump(mode="json")


@console_ns.route("/rag/pipelines/transform/datasets/<uuid:dataset_id>")
class RagPipelineTransformApi(Resource):
    @console_ns.response(200, "Success", console_ns.models[RagPipelineOpaqueResponse.__name__])
    @setup_required
    @login_required
    @account_initialization_required
    @with_current_user
    @with_session
    def post(self, session: Session, current_user: Account, dataset_id: UUID):
        if not (current_user.has_edit_permission or current_user.is_dataset_operator):
            raise Forbidden()

        dataset_id_str = str(dataset_id)
        rag_pipeline_transform_service = RagPipelineTransformService()
        result = rag_pipeline_transform_service.transform_dataset(dataset_id_str, session)

View on GitHub (pinned to ef8544b173)

Solutions

  1. Run the node first (POST .../draft/nodes/<node_id>/run) before asking for its last run.
  2. Treat this 404 as 'node has no execution history' in the UI rather than an error.
  3. Confirm node_id belongs to an executable node type.
  4. If history is expected, check retention/cleanup settings that may have removed old executions.

Example fix

// before
GET .../draft/nodes/<node>/last-run   // -> 404 last run not found
// after
await POST .../draft/nodes/<node>/run
GET .../draft/nodes/<node>/last-run
Defensive patterns

Strategy: try-catch

Validate before calling

async function getLastRunOrCreate(pipelineId, nodeId, inputs) {
  const r = await fetch(`/rag/pipelines/${pipelineId}/workflows/draft/nodes/${nodeId}/last-run`);
  if (r.status === 404) {
    await fetch(`/rag/pipelines/${pipelineId}/workflows/draft/nodes/${nodeId}/run`, { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({ inputs }) });
    return fetch(`/rag/pipelines/${pipelineId}/workflows/draft/nodes/${nodeId}/last-run`);
  }
  return r;
}

Type guard

function hasExecutionHistory(exec) { return !!exec && !!exec.id; }

Try / catch

try { return await getLastRunOrCreate(id, nodeId, inputs); } catch (e) { /* 'last run not found' handled by run-first fallback */ throw e; }

Prevention

When it happens

Trigger: Calling GET .../workflows/draft/nodes/<node_id>/last-run for a node that has never been executed (newly added node, draft saved but never run), or whose execution records were purged. The draft workflow resolves fine, but node_exec is None.

Common situations: Requesting last-run right after adding a node to the graph; node is an input/trigger type that does not create execution rows; executions cleaned up by retention.

Related errors


AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12). Data as JSON: /api/errors/0dd93078ba58761d. Report an issue: GitHub.