{"record":{"id":"977d118d94a06874","repo":"astral-sh/ruff","slug":"positional-argument-index-is-missing","errorCode":null,"errorMessage":"Positional argument {index} is missing","messagePattern":"Positional argument (.+?) is missing","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/ruff_linter/src/rules/pyupgrade/rules/f_strings.rs","lineNumber":317,"sourceCode":"                    field_name,\n                    conversion_spec,\n                    format_spec,\n                } => {\n                    converted.push('{');\n\n                    let field = FieldName::parse(&field_name)?;\n\n                    // Map from field type to specifier.\n                    let specifier = match field.field_type {\n                        FieldType::Auto => IndexOrKeyword::Index(summary.arg_auto()),\n                        FieldType::Index(index) => IndexOrKeyword::Index(index),\n                        FieldType::Keyword(name) => IndexOrKeyword::Keyword(name),\n                    };\n\n                    let arg = match &specifier {\n                        IndexOrKeyword::Index(index) => {\n                            summary.arg_positional(*index).ok_or_else(|| {\n                                anyhow::anyhow!(\"Positional argument {index} is missing\")\n                            })?\n                        }\n                        IndexOrKeyword::Keyword(name) => {\n                            summary.arg_keyword(name).ok_or_else(|| {\n                                anyhow::anyhow!(\"Keyword argument '{name}' is missing\")\n                            })?\n                        }\n                    };\n\n                    // If the argument contains a side effect, and it's repeated in the format\n                    // string, we can't convert the format string to an f-string. For example,\n                    // converting `\"{x} {x}\".format(x=foo())` would result in `f\"{foo()} {foo()}\"`,\n                    // which would call `foo()` twice.\n                    //\n                    // This is also true for builtins, so we don't treat them as special when\n                    // checking for effects here.\n                    if !seen.insert(specifier) && contains_effect(arg, |_| false) {\n                        return Ok(Self::SideEffects);","sourceCodeStart":299,"sourceCodeEnd":335,"githubUrl":"https://github.com/astral-sh/ruff/blob/26f38c119cac42e4d320ba08f09224fdec74af2c/crates/ruff_linter/src/rules/pyupgrade/rules/f_strings.rs#L299-L335","documentation":"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.","triggerScenarios":"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')`.","commonSituations":"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.","solutions":["Reproduce with a minimal file containing the offending `.format()` call and confirm Ruff fails instead of skipping it","Remove or fix the dangling positional index in the format string (every `{N}` must have a matching Nth argument)","If the specifier intentionally skips an argument, convert the string to an f-string manually so Ruff has nothing to fix","Report the crash to the Ruff maintainers; the rule should skip, not error, when an index is missing"],"exampleFix":"// before\ns = '{0} {2}'.format(a, b, c)  # only if index out of range\ns = '{1}'.format('a')\n// after\ns = f'{a} {c}'\ns = f'{\"a\"}'  # or fix to '{0}'.format('a')","handlingStrategy":"validation","validationCode":"// Python-side pre-check before relying on the UP032 fix\nimport string\n\ndef all_indices_present(template: str, *args: object) -> bool:\n    fields = [f for _, f, _, _ in string.Formatter().parse(template) if f]\n    for f in fields:\n        if f.isdigit() and int(f) >= len(args):\n            return False\n    return True\n\nassert all_indices_present(\"{0} {2}\".format(a, b, c))","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never reference {N} indices greater than or equal to the number of .format() arguments","Prefer f-strings or implicit {} placeholders to avoid index arithmetic entirely","Add a lint/test that validates template indices against arg counts for template-heavy code","When removing a .format() argument, update every specifier in the same change"],"tags":["rust","pyupgrade","format-strings","linter"],"backgroundTag":"missing-positional-argument","analyzedSha":"26f38c119cac42e4d320ba08f09224fdec74af2c","analyzedAt":"2026-09-05T10:32:37.492Z","contentChangedAt":"2026-09-05T10:32:37.492Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}