astral-sh/ruff · info

Can't use built-in `{builtin}` constructor

Error message

Can't use built-in `{builtin}` constructor

What it means

The `reimplemented-starmap` (REF414) fix builds a replacement call using the `builtin` identifier (e.g. `zip`) as the constructor of the fixed expression. Before doing so it verifies the name is still bound to the actual built-in; if shadowed, it bails and reports this error internally, so no fix is offered. This is a guard against producing incorrect fixes when user code redefines the name.

Source

Thrown at crates/ruff_linter/src/rules/refurb/rules/reimplemented_starmap.rs:294

                // ```
                try_construct_call(name, iter, func, Name::new_static("set"), checker)
            }
        }
    }
}

/// Try constructing the call to `itertools.starmap` and wrapping it with the given builtin.
fn try_construct_call(
    name: Name,
    iter: &Expr,
    func: &Expr,
    builtin: Name,
    checker: &Checker,
) -> Result<String> {
    // We can only do our fix if `builtin` identifier is still bound to
    // the built-in type.
    if !checker.semantic().has_builtin_binding(&builtin) {
        bail!("Can't use built-in `{builtin}` constructor")
    }

    // In general, we replace:
    // ```python
    // foo(...) for ... in iter
    // ```
    //
    // with:
    // ```python
    // builtin(itertools.starmap(foo, iter))
    // ```
    // where `builtin` is a constructor for a target collection.
    let call = construct_starmap_call(name, iter, func);
    let wrapped = wrap_with_call_to(call, builtin);
    Ok(checker.generator().expr(&wrapped.into()))
}

/// Construct the call to `itertools.starmap` for suggestion.

View on GitHub (pinned to 15f3fe6b15)

Solutions

  1. Apply the fix manually instead of relying on autofix: rewrite the comprehension/lambda to call the built-in `starmap` directly with an explicit qualified builtin such as `import builtins` if needed
  2. Rename the local shadowing the builtin (e.g. `map_` instead of `map`) so `zip`/`map` resolves to the builtin again, then rerun ruff
  3. Use `--unsafe-fixes` scenarios carefully: confirm the binding with `checker.semantic().has_builtin_binding` mentally before hand-editing

Example fix

# before
result = [(f(*args)) for args in pairs]  # `zip` shadowed by local function
# after (manual rewrite, since autofix is skipped)
from itertools import starmap
result = list(starmap(f, pairs))
Defensive patterns

Strategy: validation

Validate before calling

import builtins
# check the builtin is not shadowed in the module scope before relying on autofix
def builtin_not_shadowed(name):
    import ast, sys
    src = open('module.py').read()
    tree = ast.parse(src)
    for node in ast.walk(tree):
        if isinstance(node, (ast.FunctionDef, ast.ClassDef, ast.Assign)):
            targets = getattr(node, 'targets', [getattr(node, 'name', None)])
            if any(getattr(t, 'id', None) == name for t in targets if t):
                return False
    return True

print(builtin_not_shadowed('zip'))

Prevention

When it happens

Trigger: Applying the automatic fix for REF414 (`starmap` reimplemented via comprehension/lambda) when the builtin name (e.g. `zip`, `map`) is locally rebound: a local variable, function, import, or class parameter shadows it, or `del` removed the binding.

Common situations: User code defines a function or variable named `map`/`zip`/`sum` in the same scope; an `from foo import zip` import shadows the builtin; the diagnostic fires but the fixer refuses to autofix.

Related errors


AI-assisted analysis of astral-sh/ruff@15f3fe6b15 (2026-09-05). Data as JSON: /api/errors/1f33f5c28e98256c. Report an issue: GitHub.