{"record":{"id":"2995347f3b46da76","repo":"vitessio/vitess","slug":"bug-tried-to-replace-visitthis-on-visitable","errorCode":null,"errorMessage":"[BUG] tried to replace 'VisitThis' on 'Visitable'","messagePattern":"\\[BUG\\] tried to replace 'VisitThis' on 'Visitable'","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/sqlparser/ast_rewrite.go","lineNumber":16432,"sourceCode":"func (a *application) rewriteVisitable(parent SQLNode, node Visitable, 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(VisitableInner))\n\t}\n\tif !a.rewriteSQLNode(node, node.VisitThis(), func(newNode, parent SQLNode) {\n\t\tpanic(\"[BUG] tried to replace 'VisitThis' on 'Visitable'\")\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\n\t\ta.cur.node = node\n\t\tif !a.post(&a.cur) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n","sourceCodeStart":16414,"sourceCodeEnd":16449,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/sqlparser/ast_rewrite.go#L16414-L16449","documentation":"The generated rewriter for the Visitable wrapper node rewrites node.VisitThis() but its replacement callback panics because the Visitable wrapper itself cannot be swapped. Replacements must happen at the inner node level, not on the wrapper.","triggerScenarios":"A rewrite callback that returns a replacement when parent is a *Visitable wrapper (used for extension points in the AST), replacing the wrapper's inner node through the wrapper's own rewrite slot.","commonSituations":"Custom SQLNode extensions embedded via Visitable; rewriters that intercept wrapper nodes instead of the concrete inner nodes; forked ASTs after parser changes.","solutions":["Match and replace the inner node returned by VisitThis() in your callback, not the Visitable wrapper itself","Skip wrapper nodes: return (node, false) when node is a Visitable wrapper","Adjust your rewriter to operate on the concrete AST node types you care about","Regenerate with `make codegen` if your generated rewriter is out of sync with AST definitions"],"exampleFix":"// before\nfunc repl(node, parent sqlparser.SQLNode) (sqlparser.SQLNode, bool) {\n    if _, ok := parent.(*sqlparser.Visitable); ok {\n        return newInner, true // panics: cannot replace on Visitable\n    }\n    return node, false\n}\n// after\nfunc repl(node, parent sqlparser.SQLNode) (sqlparser.SQLNode, bool) {\n    if inner, ok := node.(matchingInnerType); ok {\n        return newInner, true // replace the concrete inner node\n    }\n    return node, false\n}","handlingStrategy":"validation","validationCode":"func repl(node, parent sqlparser.SQLNode) (sqlparser.SQLNode, bool) {\n    if v, ok := parent.(*sqlparser.Visitable); ok {\n        _ = v // never replace through the wrapper; target inner nodes\n        return node, false\n    }\n    return replaceIfMatched(node)\n}","typeGuard":null,"tryCatchPattern":"err := func() (err error) {\n    defer func() {\n        if r := recover(); r != nil {\n            err = fmt.Errorf(\"rewrite panicked on Visitable wrapper: %v\", r)\n        }\n    }()\n    return sqlparser.SafeRewrite(stmt, opts, repl)\n}()","preventionTips":["Match concrete inner node types, never Visitable wrappers","Return (node, false) for wrapper nodes in callbacks","Test rewriters against ASTs containing extension Visitable nodes"],"tags":["sqlparser","ast-rewrite","codegen","panic","visitable"],"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"}