astral-sh/ruff · warning

Expected each argument to be a tuple of length two

Error message

Expected each argument to be a tuple of length two

What it means

Raised during the C408 fix (`dict(...)` -> dict literal) when an element of the tuple/list argument is not a two-element (key, value) structure. The fixer maps each element to a `DictElement` and requires every element to be a pair; anything else aborts the fix.

Source

Thrown at crates/ruff_linter/src/rules/flake8_comprehensions/fixes.rs:196

                value: Expression::Tuple(tuple),
                comma,
            } = element
            {
                if let Some(Element::Simple { value: key, .. }) = tuple.elements.first() {
                    if let Some(Element::Simple { value, .. }) = tuple.elements.get(1) {
                        return Ok(DictElement::Simple {
                            key: key.clone(),
                            value: value.clone(),
                            comma: comma.clone(),
                            whitespace_before_colon: ParenthesizableWhitespace::default(),
                            whitespace_after_colon: ParenthesizableWhitespace::SimpleWhitespace(
                                SimpleWhitespace(" "),
                            ),
                        });
                    }
                }
            }
            bail!("Expected each argument to be a tuple of length two")
        })
        .collect::<Result<Vec<DictElement>>>()?;

    tree = Expression::Dict(Box::new(Dict {
        elements,
        lbrace: LeftCurlyBrace {
            whitespace_after: call.whitespace_before_args.clone(),
        },
        rbrace: RightCurlyBrace {
            whitespace_before: arg.whitespace_after_arg.clone(),
        },
        lpar: vec![],
        rpar: vec![],
    }));

    Ok(Edit::range_replacement(
        pad_expression(
            tree.codegen_stylist(stylist),

View on GitHub (pinned to 26f38c119c)

Solutions

  1. Ensure every inner tuple/list has exactly two elements; run the fixer again.
  2. Convert to a dict literal directly, which sidesteps the fixer.
  3. Suppress C408 for that line with `# noqa: C408` if the argument structure is intentionally irregular.

Example fix

// before
dict([("a", 1, "x")])
// after
dict([("a", 1)])  # or {"a": 1}
Defensive patterns

Strategy: validation

Validate before calling

pairs = [("a", 1), ("b", 2)]
assert all(isinstance(p, (tuple, list)) and len(p) == 2 for p in pairs), 'each dict() arg element must be a pair'

Type guard

def is_pair(el):
    return isinstance(el, (tuple, list)) and len(el) == 2

Try / catch

try:
    apply_autofix(diagnostic)
except Exception:
    manual_rewrite()

Prevention

When it happens

Trigger: `ruff check --fix` on `dict([('a', 1, 'extra'), ('b', 2)])` or `dict([('a',)])` where a nested tuple/list element does not have exactly length two.

Common situations: Hand-written tuple lists with malformed entries; refactored code where a third field was added to pairs; data literals pasted from elsewhere that violate dict() semantics anyway.

Related errors


AI-assisted analysis of astral-sh/ruff@26f38c119c (2026-09-05). Data as JSON: /api/errors/563836868b2cadee. Report an issue: GitHub.