astral-sh/ruff · error

Positional argument {index} is missing

Error message

Positional argument {index} is missing

What it means

Ruff's pyupgrade f-string rule converts `.format()` calls to f-strings. When a format specifier references a positional argument index that does not exist in the call's argument list (e.g. `'{1}'.format('a')`), the lookup in the call summary fails and this anyhow error aborts the conversion.

Source

Thrown at crates/ruff_linter/src/rules/pyupgrade/rules/f_strings.rs:317

                    field_name,
                    conversion_spec,
                    format_spec,
                } => {
                    converted.push('{');

                    let field = FieldName::parse(&field_name)?;

                    // Map from field type to specifier.
                    let specifier = match field.field_type {
                        FieldType::Auto => IndexOrKeyword::Index(summary.arg_auto()),
                        FieldType::Index(index) => IndexOrKeyword::Index(index),
                        FieldType::Keyword(name) => IndexOrKeyword::Keyword(name),
                    };

                    let arg = match &specifier {
                        IndexOrKeyword::Index(index) => {
                            summary.arg_positional(*index).ok_or_else(|| {
                                anyhow::anyhow!("Positional argument {index} is missing")
                            })?
                        }
                        IndexOrKeyword::Keyword(name) => {
                            summary.arg_keyword(name).ok_or_else(|| {
                                anyhow::anyhow!("Keyword argument '{name}' is missing")
                            })?
                        }
                    };

                    // If the argument contains a side effect, and it's repeated in the format
                    // string, we can't convert the format string to an f-string. For example,
                    // converting `"{x} {x}".format(x=foo())` would result in `f"{foo()} {foo()}"`,
                    // which would call `foo()` twice.
                    //
                    // This is also true for builtins, so we don't treat them as special when
                    // checking for effects here.
                    if !seen.insert(specifier) && contains_effect(arg, |_| false) {
                        return Ok(Self::SideEffects);

View on GitHub (pinned to 26f38c119c)

Solutions

  1. Reproduce with a minimal file containing the offending `.format()` call and confirm Ruff fails instead of skipping it
  2. Remove or fix the dangling positional index in the format string (every `{N}` must have a matching Nth argument)
  3. If the specifier intentionally skips an argument, convert the string to an f-string manually so Ruff has nothing to fix
  4. Report the crash to the Ruff maintainers; the rule should skip, not error, when an index is missing

Example fix

// before
s = '{0} {2}'.format(a, b, c)  # only if index out of range
s = '{1}'.format('a')
// after
s = f'{a} {c}'
s = f'{"a"}'  # or fix to '{0}'.format('a')
Defensive patterns

Strategy: validation

Validate before calling

// Python-side pre-check before relying on the UP032 fix
import string

def all_indices_present(template: str, *args: object) -> bool:
    fields = [f for _, f, _, _ in string.Formatter().parse(template) if f]
    for f in fields:
        if f.isdigit() and int(f) >= len(args):
            return False
    return True

assert all_indices_present("{0} {2}".format(a, b, c))

Prevention

When it happens

Trigger: Calling the UP032 (quoted-annotations/f-string conversion) fix on a string whose format specifiers use a positional index absent from `.format(...)` arguments, e.g. `'{1}'.format('a')` or `'{0} {2}'.format('a', 'b')`.

Common situations: Automatically formatted/edited code where `.format()` arguments were removed or reordered without updating indices; generated code with template strings referencing later args; partially refactored logging templates.

Related errors


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