Workflow Variable Size Management#
Dify enforces two complementary size controls on workflow variables: a hard creation-time limit that rejects oversized variables during variable construction, and a runtime truncation system that structure-preservingly shrinks variables before they are stored or streamed to clients.
Two Distinct Size Controls#
1. MAX_VARIABLE_SIZE β Creation-time hard limit#
MAX_VARIABLE_SIZE (default 200 KB, set in WorkflowConfig) is checked in variable_factory._build_variable_from_mapping(). If a newly constructed variable's .size exceeds the limit, a VariableError is raised immediately. This prevents oversized variables from ever entering the workflow graph.
# api/configs/feature/__init__.py β WorkflowConfig
MAX_VARIABLE_SIZE: PositiveInt = Field(default=200 * 1024, ...) # 200 KiB
2. WORKFLOW_VARIABLE_TRUNCATION_* β Runtime truncation limits#
A separate config class WorkflowVariableTruncationConfig controls the runtime truncation pipeline:
| Env variable | Default | Purpose |
|---|---|---|
WORKFLOW_VARIABLE_TRUNCATION_MAX_SIZE | 1,000 KiB | Max total bytes before triggering final truncation |
WORKFLOW_VARIABLE_TRUNCATION_STRING_LENGTH | 100,000 chars | Per-string character limit |
WORKFLOW_VARIABLE_TRUNCATION_ARRAY_LENGTH | 1,000 elements | Per-array element limit |
All three values are loaded from environment variables and feed the VariableTruncator.default() factory method.
VariableTruncator β Structure-preserving truncation#
api/services/variable_truncator.py implements the core truncation logic. The main class, VariableTruncator, supports two entry points:
truncate(segment)β Truncates a singleSegment. Strings are capped at_string_length_limit; arrays and objects are recursively trimmed to fit_max_size_bytes. If the result still exceeds the max, the value is serialized to a JSON string and hard-truncated as a last resort.truncate_variable_mapping(v)β Truncates a key-value mapping (e.g.,inputs,process_data,outputsof aWorkflowNodeExecutionrecord) by distributing the remaining byte budget across entries proportionally.
Size accounting avoids repeated JSON serialization via calculate_json_size(), which recursively estimates the serialized JSON byte count from the in-memory value.
Per-type truncation strategies#
| Type | Strategy |
|---|---|
StringSegment | Truncate to _string_length_limit chars + "..." |
ArraySegment | Cap at _array_element_limit items; then truncate individual items to remaining budget |
ObjectSegment | Sort keys for determinism; trim values proportionally; drop trailing keys if budget exhausted |
NoneSegment, IntegerSegment, FloatSegment, BooleanSegment, FileSegment, ArrayFileSegment | Never truncated β returned as-is |
Object truncation keeps all keys when possible, dropping from the end only when the budget is exhausted. The maximum recursion depth is capped at 100 to prevent stack overflow.
DummyVariableTruncator β Service API no-op#
DummyVariableTruncator implements BaseTruncator but passes all values through unchanged. It is injected in WorkflowResponseConverter.__init__() when invoke_from == InvokeFrom.SERVICE_API, preserving backward-compatible full-fidelity responses for Service API callers.
Call Sites#
| Location | Method called | Notes |
|---|---|---|
WorkflowResponseConverter | truncate_variable_mapping() | Applied to node inputs/outputs in stream responses |
sqlalchemy_workflow_node_execution_repository._truncate_and_upload() | truncate_variable_mapping() | Applied before persisting node execution records to RDBMS |
workflow_draft_variable_service._try_offload_large_variable() | truncate() | Applied to oversized draft variables |
Key files#
api/services/variable_truncator.pyβVariableTruncator,DummyVariableTruncator,BaseTruncatorapi/configs/feature/__init__.pyβWorkflowConfig.MAX_VARIABLE_SIZE,WorkflowVariableTruncationConfigapi/factories/variable_factory.pyβ Creation-time size check at line 118β119api/core/app/apps/common/workflow_response_converter.pyβ Truncator selection (real vs. no-op)