langgenius/dify · error · InvalidArgumentError

expected dict for files[0], got {type(raw_value)}

Error message

expected dict for files[0], got {type(raw_value)}

What it means

Returned (HTTP 400, `invalid_param`) by PATCH on an ARRAY_FILE variable when `value` is a non-empty list but its first element is not a dict. The handler checks `raw_value[0]` to fail fast before calling `build_from_mappings`, which would otherwise crash on a non-mapping element. Note the error message string still prints `type(raw_value)` (the list) rather than the element type — a known cosmetic bug.

Source

Thrown at api/controllers/console/datasets/rag_pipeline/rag_pipeline_draft_variable.py:260

        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)
        draft_var_srv.update_variable(variable, name=new_name, value=new_value)
        db.session.commit()
        return variable

    @console_ns.response(204, "Variable deleted successfully")
    @_api_prerequisite
    def delete(self, _current_user: Account, pipeline: Pipeline, variable_id: UUID):
        draft_var_srv = WorkflowDraftVariableService(
            session=db.session(),
        )

View on GitHub (pinned to ef8544b173)

Solutions

  1. Ensure every element of the `value` array is a file-mapping object.
  2. Map each id to its object before send: `value: ids.map(id => ({ type, transfer_method, upload_file_id: id }))`.
  3. Reject mixed-type arrays client-side before PATCH.
  4. When the list is non-empty, validate `Array.isArray(value) && value.every(v => v && typeof v === 'object')`.

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 asFileMappingArray(v: unknown): object[] {
  if (!Array.isArray(v)) throw new Error('value must be array')
  if (v.length > 0 && (typeof v[0] !== 'object' || v[0] === null || Array.isArray(v[0]))) {
    throw new Error('array elements must be file mapping objects')
  }
  return v as object[]
}

Type guard

function isFileMappingArray(v: unknown): v is object[] {
  return Array.isArray(v) && (v.length === 0 || (typeof v[0] === 'object' && v[0] !== null && !Array.isArray(v[0])))
}

Try / catch

try {
  await patch(...)
} catch (e) {
  if (e.code === 'invalid_param' && /expected dict for files\[0\]/.test(e.message)) {
    // map each element id -> mapping object, retry once
  } else throw e
}

Prevention

When it happens

Trigger: Sending `"value": ["<upload_file_id>"]` (list of strings) instead of a list of objects; mixing object and string elements with a string at index 0; passing a list parsed from a flat CSV.

Common situations: Frontend mapping over selected files and emitting only their ids. API gateway that flattens nested objects. Test fixtures building the array from string columns.

Related errors


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