File Array Handling in Dify Workflows#
Dify supports Array[File] as a first-class variable type in workflows, but file variables face specific restrictions in certain nodes. The Code node blocks file-type inputs at the UI layer, while the Variable Aggregator and type system treat file variables normally.
Code Node: File Variable Restrictions#
The Code node panel renders its input variable list with isSupportFileVar={false} on the VarList component. This is a UI-layer restriction: file-type and Array[File] variables are hidden from the variable picker when configuring Code node inputs .
Despite this UI restriction, the filterVar function in use-config.ts explicitly includes VarType.file and VarType.arrayFile in its allowed types list. This apparent inconsistency means the variable picker won't show file variables (panel-level block), but the filter logic is permissiveβa manually-constructed or legacy DSL referencing file variables may still load.
Why the sandbox restriction matters: The Code node sends inputs to dify-sandbox (a separate Go process) as JSON-serialized, base64-encoded data via TemplateTransformer.serialize_inputs() using dumps_with_segments. The sandbox runs in a seccomp-restricted container with no access to Dify's file storage. Even if a file segment was passed, the sandbox would receive only the metadata dict (url, name, mime_type, etc.), not the raw file bytes.
Code nodes cannot modify conversation variablesβthey run in the sandboxed environment with no API to write back to the workflow's variable pool .
Variable Aggregator: Array[File] Support#
The Variable Aggregator node (api/dify_graph/nodes/variable_aggregator/, formerly api/core/workflow/nodes/variable_aggregator/) does support file-type variables. PR #24689 fixed a bug where file type variables could not be selected in the aggregator's variable picker. The AddVariablePopup component now passes isSupportFileVar={true} to VarReferenceVars.
Aggregation modes (controlled by VariableAggregatorNodeData):
| Mode | Behavior |
|---|---|
| Simple (default) | Returns first non-None value from the selector list under key "output" |
Grouped (group_enabled=True) | Returns first non-None value per group under the group's group_name key |
Aggregate All (aggregate_all=True) | Collects all resolved inputs into a listβuseful for parallel branches (e.g., Knowledge Retrieval) |
The "first found" semantics naturally handle skipped branches: absent variables simply aren't in the pool and are skipped .
Key limitation: The aggregator acts as a selector, not a merger. It cannot merge two Array[File] variables from parallel branches into a single combined array. Each aggregator produces one output variable. To collect files from N branches, you need N aggregator nodes .
Array[File] in the Variable Type System#
ArrayFileSegment (and FileSegment) are first-class variable types in Dify. As of PR #39218, VariableTruncator properly truncates list[File] arrays according to both the element-count cap (array_element_limit, default 20) and the byte budget (max_size_bytes, default 1000 KB). Individual File elements are not truncatedβeach File is returned as-is with its real serialized sizeβbut the array itself is capped and counted like any other array type. This fixes a bug where a "Dirty fix" branch unconditionally appended all File elements before checking limits .
Variable creation enforces a 200 KB hard limit via MAX_VARIABLE_SIZE in WorkflowConfigβbut file segments (which store metadata, not content) rarely hit this .
Common Issues#
"Variable Not Found" at branch convergence: If a conditional branch is skipped, its output variables are absent from the pool. Downstream nodes referencing them throw an error before Jinja2 templates are evaluated. The fix is to route variables through a Variable Aggregator node (one per variable). See issue #38655 and discussion #38799.
Array[File] manipulation: You cannot loop, filter, or transform an Array[File] variable using the Code node (blocked at input picker). Workarounds:
- Use the HTTP Request node with file URLs extracted via template substitution.
- Restructure to process file metadata (extracted string fields) via Code and pass file references separately.
Agent node and legacy userinput.files: The Start node may have a legacy Array[File] field (userinput.files) that cannot be deleted. Agent nodes validate all tool parameters and fail if a file-type variable exists and no file tool is enabled (issue #33976).
Key Source Files#
| File | Purpose |
|---|---|
web/app/components/workflow/nodes/code/panel.tsx | Code node panelβisSupportFileVar={false} blocks file input selection |
web/app/components/workflow/nodes/code/use-config.ts | filterVarβpermissive type list including arrayFile |
web/app/components/workflow/nodes/_base/components/add-variable-popup.tsx | Variable Aggregator variable pickerβisSupportFileVar enabled |
api/core/helper/code_executor/template_transformer.py | serialize_inputs()βJSON/base64 encoding for sandbox |
api/services/variable_truncator.py | list[File] arrays now truncated per array_element_limit and byte budget; individual File elements returned as-is |