{"record":{"id":"16b93bf20aad96d7","repo":"vitessio/vitess","slug":"slow-path-for-n-directive-for-slice-of-type-othe","errorCode":null,"errorMessage":"slow path for `n` directive for slice of type other than Expr","messagePattern":"slow path for `n` directive for slice of type other than Expr","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/tools/astfmtgen/main.go","lineNumber":269,"sourceCode":"\t\t\tinputExpr := expr.Args[2+fieldnum]\n\t\t\tinputType := r.pkg.TypesInfo.Types[inputExpr].Type\n\t\t\tsliceType, ok := inputType.(*types.Slice)\n\t\t\tif !ok {\n\t\t\t\tpanic(\"'%n' directive requires a slice\")\n\t\t\t}\n\t\t\tif types.Implements(sliceType.Elem(), r.astExpr) {\n\t\t\t\t// Fast path: input is []Expr\n\t\t\t\tcall := &ast.CallExpr{\n\t\t\t\t\tFun: &ast.SelectorExpr{\n\t\t\t\t\t\tX:   callexpr.X,\n\t\t\t\t\t\tSel: &ast.Ident{Name: \"formatExprs\"},\n\t\t\t\t\t},\n\t\t\t\t\tArgs: []ast.Expr{inputExpr},\n\t\t\t\t}\n\t\t\t\tcursor.InsertBefore(&ast.ExprStmt{X: call})\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tpanic(\"slow path for `n` directive for slice of type other than Expr\")\n\t\tdefault:\n\t\t\tpanic(fmt.Sprintf(\"unsupported escape %q\", token))\n\t\t}\n\t\tfieldnum++\n\t\ti++\n\t}\n\n\tcursor.Delete()\n\treturn true\n}\n\nvar noQualifier = func(p *types.Package) string {\n\treturn \"\"\n}\n","sourceCodeStart":251,"sourceCodeEnd":284,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/tools/astfmtgen/main.go#L251-L284","documentation":"The %n directive has a fast path for slices whose element type implements ast.Expr, which the generator knows how to emit. A slice of any other element type has no implemented code path, so the tool panics explicitly rather than generating incorrect output — this is a deliberate 'not implemented' guard.","triggerScenarios":"A %n directive's argument is a slice, but its element type does not implement ast.Expr, e.g. []ast.Stmt, []*ast.Field, or []string passed to ast_sprintf with %n.","commonSituations":"Assuming %n works for any node slice (it only supports ast.Expr implementations); refactoring a field from []ast.Expr to another node-kind slice while keeping the %n verb; adding a new AST node kind slice without extending astfmtgen.","solutions":["Change the argument to a []Expr-compatible slice (element type implementing ast.Expr), or cast/collect the values as ast.Expr first.","Use %v for non-Expr slices instead of %n.","If Expr-slice support is genuinely required, extend rewriteAstPrintf in go/tools/astfmtgen/main.go to emit the slow path."],"exampleFix":"// before\nast_sprintf(body, \"%n\", body.Stmts) // []ast.Stmt: panics\n// after\nast_sprintf(body, \"%v\", body.Stmts)","handlingStrategy":"fallback","validationCode":"// before using %n, confirm the element type implements ast.Expr\n elem := sliceType.Elem()\n if !types.Implements(elem, exprInterfaceType) {\n    // fall back to %v instead of %n\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat %n as strictly 'slice of ast.Expr'; use %v for []ast.Stmt, []*ast.Field, etc.","Convert other node-kind slices to []ast.Expr only when the elements truly implement ast.Expr.","Extend astfmtgen deliberately (with tests) before introducing new %n element types."],"tags":["go","codegen","tooling","panic","astfmtgen","unsupported-type"],"backgroundTag":"format-directive-type-mismatch","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}