langgenius/dify · error · ValueError

missing inputs

Error message

missing inputs

What it means

Bare ValueError('missing inputs') raised inside DraftWorkflowNodeRunApi.post (POST /apps/{app_id}/workflows/draft/nodes/{node_id}/run) when args_model.inputs is None. DraftWorkflowNodeRunPayload declares inputs as Optional, so a request omitting the inputs field (or sending it as null) reaches the handler. Because this handler does not catch ValueError, it propagates to Flask and surfaces as an HTTP 400 with message 'missing inputs'.

Source

Thrown at api/controllers/console/app/workflow.py:1230

    @console_ns.response(403, "Permission denied")
    @console_ns.response(404, "Node not found")
    @setup_required
    @login_required
    @account_initialization_required
    @rbac_permission_required(RBACResourceScope.APP, RBACPermission.APP_TEST_AND_RUN)
    @get_app_model(mode=[AppMode.ADVANCED_CHAT, AppMode.WORKFLOW])
    @with_current_user
    @edit_permission_required
    def post(self, current_user: Account, app_model: App, node_id: str):
        """
        Run draft workflow node
        """
        args_model = DraftWorkflowNodeRunPayload.model_validate(console_ns.payload or {})
        args = args_model.model_dump(exclude_none=True)

        user_inputs = args_model.inputs
        if user_inputs is None:
            raise ValueError("missing inputs")

        workflow_srv = WorkflowService()
        # fetch draft workflow by app_model
        draft_workflow = workflow_srv.get_draft_workflow(app_model=app_model, session=db.session())
        if not draft_workflow:
            raise ValueError("Workflow not initialized")
        files = _parse_file(draft_workflow, args.get("files"))
        workflow_service = WorkflowService()

        workflow_node_execution = workflow_service.run_draft_workflow_node(
            app_model=app_model,
            draft_workflow=draft_workflow,
            node_id=node_id,
            user_inputs=user_inputs,
            account=current_user,
            query=args.get("query", ""),
            files=files,
        )

View on GitHub (pinned to ef8544b173)

Solutions

  1. Always include an 'inputs' object in the request body, even an empty {} when there are no variables.
  2. If using DraftWorkflowNodeRunPayload, set inputs to {} rather than leaving it null.
  3. Add client-side validation that inputs is non-null before sending.

Example fix

// before: inputs omitted
{ "query": "hi" }
// after: inputs present (empty is fine)
{ "inputs": {}, "query": "hi" }
Defensive patterns

Strategy: validation

Validate before calling

// Ensure inputs is always an object before sending.
if (body.inputs === undefined || body.inputs === null) body.inputs = {};

Type guard

const hasInputs = (b): b is {inputs: Record<string, unknown>} =>
  !!b && b.inputs !== null && b.inputs !== undefined && typeof b.inputs === 'object';

Try / catch

try {
  return await runDraftNode(appId, nodeId, body);
} catch (e) {
  if (e?.status === 400 && /missing inputs/i.test(e?.message)) {
    body.inputs = {}; return retry();
  }
  throw e;
}

Prevention

When it happens

Trigger: Posting a node-run request whose JSON body omits 'inputs' or sets it to null; sending only query/files without the inputs object.

Common situations: Frontend builds the payload conditionally and skips inputs when the node has no variables; a schema change made inputs optional where callers previously always sent it; raw API client not including inputs.

Related errors


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