{"record":{"id":"ee0c4c2a8ca43af5","repo":"astral-sh/ruff","slug":"isinstance-should-have-two-arguments","errorCode":null,"errorMessage":"`isinstance` should have two arguments","messagePattern":"`isinstance` should have two arguments","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/ruff_linter/src/rules/flake8_simplify/rules/ast_bool_op.rs","lineNumber":382,"sourceCode":"                .push(index);\n        } else {\n            last_target_option = Some(target.into());\n            duplicates.push(vec![index]);\n        }\n    }\n\n    // Generate a `Diagnostic` for each duplicate.\n    for indices in duplicates {\n        if indices.len() > 1 {\n            // Grab the target used in each duplicate `isinstance` call (e.g., `obj` in\n            // `isinstance(obj, int)`).\n            let target = if let Expr::Call(ast::ExprCall {\n                arguments: Arguments { args, .. },\n                ..\n            }) = &values[indices[0]]\n            {\n                args.first()\n                    .expect(\"`isinstance` should have two arguments\")\n            } else {\n                unreachable!(\"Indices should only contain `isinstance` calls\")\n            };\n            let mut diagnostic = checker.report_diagnostic(\n                DuplicateIsinstanceCall {\n                    name: if let Expr::Name(ast::ExprName { id, .. }) = target {\n                        Some(id.to_string())\n                    } else {\n                        None\n                    },\n                },\n                expr.range(),\n            );\n            if !contains_effect(target, |id| checker.semantic().has_builtin_binding(id)) {\n                // Flatten the type expressions from each duplicate `isinstance` call into the\n                // elements they would contribute to the merged tuple. Tuple operands splice\n                // their elements; everything else contributes itself.\n                let flattened: Vec<&Expr> = indices","sourceCodeStart":364,"sourceCodeEnd":400,"githubUrl":"https://github.com/astral-sh/ruff/blob/15f3fe6b15a5f00172f34b0f542f8ea277f5a586/crates/ruff_linter/src/rules/flake8_simplify/rules/ast_bool_op.rs#L364-L400","documentation":"The duplicate-isinstance rule assumes every collected index points to an `isinstance` call whose first positional argument (the object being tested) exists. `args.first().expect(\"`isinstance` should have two arguments\")` panics if the call has no positional arguments. Real `isinstance(x, T)` calls always have two args, so this is a defensive invariant.","triggerScenarios":"Reachable only through AST states that don't occur in valid Python: an `isinstance` call with zero positional arguments (e.g. `isinstance()`), which is a syntax/parse-level error normally rejected earlier, or a mis-tagged index in `values`/`indices`.","commonSituations":"Contributors hit this when the loop collects indices for call expressions that are not actually `isinstance` calls (e.g. after a refactor of the filter predicate), or when testing against error-tolerant parses of invalid code.","solutions":["Filter collected indices to calls with `args.len() >= 2` instead of relying on the expect","Replace the expect with `args.first()?` and skip the diagnostic when the arg is missing","Confirm the index-collection predicate still matches exactly `isinstance` calls with two arguments"],"exampleFix":"// before\nlet target = args.first().expect(\"`isinstance` should have two arguments\");\n// after\nlet Some(target) = args.first() else { continue; };","handlingStrategy":"type-guard","validationCode":"// Only collect indices of calls with a first positional arg\nif call.arguments.args.first().is_some() { indices.push(i); }","typeGuard":"fn is_two_arg_isinstance(expr: &Expr) -> bool {\n    matches!(expr, Expr::Call(c) if c.arguments.args.len() >= 2)\n}","tryCatchPattern":null,"preventionTips":["Filter indices by argument count at collection time","Never index into args without a first()/get() guard","Add mdtests for malformed isinstance calls"],"tags":["rust","panic","ast","flake8-simplify"],"backgroundTag":"unexpected-ast-shape-panic","analyzedSha":"15f3fe6b15a5f00172f34b0f542f8ea277f5a586","analyzedAt":"2026-09-05T10:32:37.492Z","contentChangedAt":"2026-09-05T10:32:37.492Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}