langgenius/dify · error · InvalidArgumentError
expected dict for file, got {type(raw_value)}
Error message
expected dict for file, got {type(raw_value)} What it means
Returned (HTTP 400, error_code `invalid_param`) by PATCH on a draft variable whose `value_type` is `SegmentType.FILE`. The handler expects the request body `value` field to be a JSON object (a file mapping with type/transfer_method/url/upload_file_id) so it can be passed to `build_from_mapping`. If `value` is a string, number, list, or null-shaped non-dict, the isinstance check fails and InvalidArgumentError is raised before any DB write.
Source
Thrown at api/controllers/console/datasets/rag_pipeline/rag_pipeline_draft_variable.py:250
variable_id_str = str(variable_id)
variable = draft_var_srv.get_variable(variable_id=variable_id_str)
if variable is None:
raise NotFoundError(description=f"variable not found, id={variable_id_str}")
if variable.app_id != pipeline.id:
raise NotFoundError(description=f"variable not found, id={variable_id_str}")
new_name = args.get(self._PATCH_NAME_FIELD, None)
raw_value = args.get(self._PATCH_VALUE_FIELD, None)
if new_name is None and raw_value is None:
return variable
new_value = None
if raw_value is not None:
match variable.value_type:
case SegmentType.FILE:
if not isinstance(raw_value, dict):
raise InvalidArgumentError(description=f"expected dict for file, got {type(raw_value)}")
raw_value = build_from_mapping(
mapping=raw_value,
tenant_id=pipeline.tenant_id,
access_controller=_file_access_controller,
)
case SegmentType.ARRAY_FILE:
if not isinstance(raw_value, list):
raise InvalidArgumentError(description=f"expected list for files, got {type(raw_value)}")
if len(raw_value) > 0 and not isinstance(raw_value[0], dict):
raise InvalidArgumentError(description=f"expected dict for files[0], got {type(raw_value)}")
raw_value = build_from_mappings(
mappings=raw_value,
tenant_id=pipeline.tenant_id,
access_controller=_file_access_controller,
)
case _:
pass
new_value = build_segment_with_type(variable.value_type, raw_value)View on GitHub (pinned to ef8544b173)
Solutions
- Send `value` as an object matching the file mapping shape: `{"type":"image","transfer_method":"local_file","upload_file_id":"<id>"}`.
- For remote files use `{"type":"image","transfer_method":"remote_url","url":"<signed url>"}`.
- Inspect `variable.value_type` from the GET response and only attach a file mapping when it equals `file`.
- Add a client-side schema validator (Pydantic/zod) for the file mapping before PATCH.
Example fix
// before
{ "value": "daded54f-72c7-4f8e-9d18-9b0abdd9f190" }
// after
{
"value": {
"type": "image",
"transfer_method": "local_file",
"upload_file_id": "daded54f-72c7-4f8e-9d18-9b0abdd9f190"
}
} Defensive patterns
Strategy: type-guard
Validate before calling
function asFileMapping(v: unknown): { type: string; transfer_method: string; upload_file_id?: string; url?: string } {
if (!v || typeof v !== 'object' || Array.isArray(v)) {
throw new Error('file value must be a mapping object')
}
const o = v as Record<string, unknown>
if (typeof o.type !== 'string' || typeof o.transfer_method !== 'string') {
throw new Error('file mapping requires string `type` and `transfer_method`')
}
return o as any
}
// before PATCH:
if (variable.value_type === 'file') rawValue = asFileMapping(rawValue) Type guard
function isFileMapping(v: unknown): v is { type: string; transfer_method: string; upload_file_id?: string; url?: string } {
return (
!!v &&
typeof v === 'object' &&
!Array.isArray(v) &&
typeof (v as any).type === 'string' &&
typeof (v as any).transfer_method === 'string'
)
} Try / catch
try {
await patch(...)
} catch (e) {
if (e.code === 'invalid_param' && /expected dict for file/.test(e.message)) {
// rewrap value as a file mapping and retry once
} else throw e
} Prevention
- Bind the file picker to the full mapping object, not the upload_file_id string.
- Validate `typeof value === 'object' && !Array.isArray(value)` before PATCH when value_type is `file`.
- Document the expected mapping shape next to the form that produces it.
- Add a Pydantic/zod schema for the file mapping on the client.
When it happens
Trigger: PATCHing a FILE-typed variable with `"value": "<upload_file_id>"` (string) instead of an object; sending `"value": [...]`; sending a bare upload_file_id string; client serializing the file object to a string before sending.
Common situations: Frontend form binding the file picker to a string id instead of the mapping object. Misreading the API doc and assuming value is the upload_file_id. Migration scripts that previously stored file ids as strings.
Related errors
- expected list for files, got {type(raw_value)}
- expected dict for files[0], got {type(raw_value)}
- Draft workflow not found, pipeline_id={pipeline.id}
- draft_workflow_not_exist
- draft_workflow_not_exist
AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12).
Data as JSON: /api/errors/c378982b2168a959.
Report an issue: GitHub.