{"record":{"id":"76fc69192b4206d2","repo":"vitessio/vitess","slug":"vt13001-76fc69","errorCode":"VT13001","errorMessage":"a derived table should never be a routed table","messagePattern":"a derived table should never be a routed table","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtgate/planbuilder/operators/route.go","lineNumber":450,"sourceCode":"\treturn nil\n}\n\n// createRouteFromTable creates a route from the given VSchema table.\nfunc createRouteFromVSchemaTable(\n\tctx *plancontext.PlanningContext,\n\tqueryTable *QueryTable,\n\tvschemaTable *vindexes.BaseTable,\n\tplanAlternates bool,\n\ttargeted Routing,\n) *Route {\n\tif vschemaTable.Name.String() != queryTable.Table.Name.String() {\n\t\t// we are dealing with a routed table\n\t\tqueryTable = queryTable.Clone()\n\t\tname := queryTable.Table.Name\n\t\tqueryTable.Table.Name = vschemaTable.Name\n\t\tastTable, ok := queryTable.Alias.Expr.(sqlparser.TableName)\n\t\tif !ok {\n\t\t\tpanic(vterrors.VT13001(\"a derived table should never be a routed table\"))\n\t\t}\n\t\trealTableName := sqlparser.NewIdentifierCS(vschemaTable.Name.String())\n\t\tastTable.Name = realTableName\n\t\tif queryTable.Alias.As.IsEmpty() {\n\t\t\t// if the user hasn't specified an alias, we'll insert one here so the old table name still works\n\t\t\tqueryTable.Alias.As = sqlparser.NewIdentifierCS(name.String())\n\t\t}\n\t}\n\tplan := &Route{\n\t\tunaryOperator: newUnaryOp(&Table{\n\t\t\tQTable: queryTable,\n\t\t\tVTable: vschemaTable,\n\t\t}),\n\t}\n\n\t// We create the appropriate Routing struct here, depending on the type of table we are dealing with.\n\tvar routing Routing\n\tif targeted != nil {","sourceCodeStart":432,"sourceCodeEnd":468,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtgate/planbuilder/operators/route.go#L432-L468","documentation":"VT13001 is Vitess' internal-error code. While rewriting a routed table reference, the planner expects the query table's alias expression to be a plain TableName; if it is a derived table (subquery in FROM), that invariant is broken, meaning a routed table is being defined via a derived table expression — never valid.","triggerScenarios":"A vschema defines a routed table whose resolution path encounters a derived-table (aliased subquery) AST node instead of a TableName in createRouteFromVSchemaTable.","commonSituations":"Misconfigured vschema routed_table entries conflicting with subquery-based queries; planner bugs where a routed table resolves through a derived table.","solutions":["Check the vschema: the routed table's target should be a real table, not something resolvable through a derived table","Rewrite the query to reference the underlying table directly instead of via a subquery alias","File a bug with query + vschema if this occurs with a valid configuration"],"exampleFix":"// vschema before\n\"route_target\": {\"type\": \"routed\", \"target\": \"...\"} // resolves via subquery\n// after\n\"real_table\": {\"type\": \"routed\", \"target\": \"ks.real_table\"} // point at a concrete table","handlingStrategy":"validation","validationCode":"// validate vschema routed tables resolve to concrete tables, not subquery aliases\n// before deploying, run the query through vtexplain / vtgate with the vschema","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep routed_table targets pointing at concrete tables","Test vschema changes with representative queries (including subqueries) in vtexplain","Report VT13001 with query + vschema — it indicates a planner bug"],"tags":["internal","planbuilder","vschema","routed-table"],"backgroundTag":"planner-internal-invariant-violation","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}