{"record":{"id":"9bf21b01eef803fd","repo":"vitessio/vitess","slug":"bug-tried-to-replace-name-on-tablename","errorCode":null,"errorMessage":"[BUG] tried to replace 'Name' on 'TableName'","messagePattern":"\\[BUG\\] tried to replace 'Name' on 'TableName'","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/sqlparser/ast_rewrite.go","lineNumber":13141,"sourceCode":"func (a *application) rewriteTableName(parent SQLNode, node TableName, replacer replacerFunc) bool {\n\tif a.pre != nil {\n\t\ta.cur.replacer = replacer\n\t\ta.cur.parent = parent\n\t\ta.cur.node = node\n\t\tkontinue := !a.pre(&a.cur)\n\t\tif a.cur.revisit {\n\t\t\ta.cur.revisit = false\n\t\t\treturn a.rewriteSQLNode(parent, a.cur.node, replacer)\n\t\t}\n\t\tif kontinue {\n\t\t\treturn true\n\t\t}\n\t}\n\tif a.collectPaths {\n\t\ta.cur.current.AddStep(uint16(TableNameName))\n\t}\n\tif !a.rewriteIdentifierCS(node, node.Name, func(newNode, parent SQLNode) {\n\t\tpanic(\"[BUG] tried to replace 'Name' on 'TableName'\")\n\t}) {\n\t\treturn false\n\t}\n\tif a.collectPaths {\n\t\ta.cur.current.Pop()\n\t\ta.cur.current.AddStep(uint16(TableNameQualifier))\n\t}\n\tif !a.rewriteIdentifierCS(node, node.Qualifier, func(newNode, parent SQLNode) {\n\t\tpanic(\"[BUG] tried to replace 'Qualifier' on 'TableName'\")\n\t}) {\n\t\treturn false\n\t}\n\tif a.collectPaths {\n\t\ta.cur.current.Pop()\n\t}\n\tif a.post != nil {\n\t\ta.cur.replacer = replacer\n\t\ta.cur.parent = parent","sourceCodeStart":13123,"sourceCodeEnd":13159,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/sqlparser/ast_rewrite.go#L13123-L13159","documentation":"Generated rewriter code for TableName.Name uses rewriteIdentifierCS, whose replacement callback panics because TableName.Name cannot be rewritten in place — replacing a column name via the path rewriter would break identifier semantics handled elsewhere (e.g. colVindex rewriting tracks identifiers separately).","triggerScenarios":"A custom rewriter's callback returns a replacement node when the visited child is a TableName's Name field (an identifiers.ColIdent), via astRewriteVisitor/RewriteOptions that rewrite identifier nodes.","commonSituations":"Rewriters that generically replace all SQLNode children including identifier fields; migrating old rewrite logic to the newer path-based rewriter; using a rewriter intended for expression nodes on whole statements.","solutions":["Do not return replacements for identifier (ColIdent/TableIdent) fields in the rewrite callback; handle name rewriting by mutating node.Name directly before/after rewriting","Restrict the rewrite callback to replaceable node types (expressions, table names as whole nodes)","Use a targeted AST manipulation (sqlparser.Rewrite or manual assignment) for identifier changes","Regenerate via `make codegen` if your local generated files are stale"],"exampleFix":"// before\nfunc repl(node, parent sqlparser.SQLNode) (sqlparser.SQLNode, bool) {\n    if ident, ok := node.(sqlparser.IdentifierCS); ok {\n        return newIdent, true // panics on TableName.Name\n    }\n    return node, false\n}\n// after\nfunc repl(node, parent sqlparser.SQLNode) (sqlparser.SQLNode, bool) {\n    if tbl, ok := node.(*sqlparser.TableName); ok {\n        tbl.Name = sqlparser.NewTableIdent(newName)\n    }\n    return node, false\n}","handlingStrategy":"validation","validationCode":"func repl(node, parent sqlparser.SQLNode) (sqlparser.SQLNode, bool) {\n    switch node.(type) {\n    case sqlparser.IdentifierCS, sqlparser.IdentifierCI:\n        return node, false // identifiers are not replaceable\n    }\n    return replaceIfMatched(node)\n}","typeGuard":"func isReplaceableNode(node sqlparser.SQLNode) bool {\n    switch node.(type) {\n    case sqlparser.IdentifierCS, sqlparser.IdentifierCI:\n        return false\n    default:\n        return true\n    }\n}","tryCatchPattern":"err := func() (err error) {\n    defer func() {\n        if r := recover(); r != nil {\n            err = fmt.Errorf(\"rewrite panicked on identifier: %v\", r)\n        }\n    }()\n    return sqlparser.SafeRewrite(stmt, opts, repl)\n}()","preventionTips":["Never return replacements for IdentifierCS/IdentifierCI fields","Rename table/column identifiers by direct field assignment","Scope rewrite callbacks to specific node types","Add regression tests covering statements with qualified table names"],"tags":["sqlparser","ast-rewrite","codegen","panic","identifiers"],"backgroundTag":"invalid-ast-rewrite-replacement","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}