{"record":{"id":"09db353b47c58213","repo":"vitessio/vitess","slug":"w-cluster-id-is-required","errorCode":null,"errorMessage":"%w: cluster ID is required","messagePattern":"%w: cluster ID is required","errorType":"validation","errorClass":"ErrInvalidRequest","httpStatus":null,"severity":"warning","filePath":"go/vt/vtadmin/api.go","lineNumber":2669,"sourceCode":"\tcanonicalQuery := sqlparser.String(vexplainStmt)\n\tresponse, err := c.DB.VExplain(ctx, canonicalQuery, vexplainStmt)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn response, nil\n}\n\n// VTExplain is part of the vtadminpb.VTAdminServer interface.\nfunc (api *API) VTExplain(ctx context.Context, req *vtadminpb.VTExplainRequest) (*vtadminpb.VTExplainResponse, error) {\n\t// TODO (andrew): https://github.com/vitessio/vitess/issues/12161.\n\tlog.Warn(\"VTAdminServer.VTExplain is deprecated; please use a vexplain query instead. For more details, see https://vitess.io/docs/user-guides/sql/vexplain/.\")\n\n\tspan, ctx := trace.NewSpan(ctx, \"API.VTExplain\")\n\tdefer span.Finish()\n\n\tif req.Cluster == \"\" {\n\t\treturn nil, fmt.Errorf(\"%w: cluster ID is required\", errors.ErrInvalidRequest)\n\t}\n\n\tif req.Keyspace == \"\" {\n\t\treturn nil, fmt.Errorf(\"%w: keyspace name is required\", errors.ErrInvalidRequest)\n\t}\n\n\tif req.Sql == \"\" {\n\t\treturn nil, fmt.Errorf(\"%w: SQL query is required\", errors.ErrInvalidRequest)\n\t}\n\n\tc, err := api.getClusterForRequest(req.Cluster)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tspan.Annotate(\"keyspace\", req.Keyspace)\n\tcluster.AnnotateSpan(c, span)\n","sourceCodeStart":2651,"sourceCodeEnd":2687,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtadmin/api.go#L2651-L2687","documentation":"The deprecated VTExplain RPC validates req.Cluster and returns this ErrInvalidRequest-wrapped error when it is empty. This endpoint is deprecated in favor of VExplain, so the durable fix is to migrate off it.","triggerScenarios":"Calling API.VTExplain with req.Cluster == \"\" (or using an old client that never populated the Cluster field).","commonSituations":"Old scripts/SDKs predating the VExplain rename; refactoring requests from VTExplain to VExplain left the deprecated call path with unset fields; deprecation warnings ignored until the field name mismatch surfaced.","solutions":["Migrate to the VExplain API, setting ClusterId, Keyspace, and Sql","If VTExplain must still be used, populate req.Cluster with the registered cluster ID","Update old clients/scripts still calling VTExplain"],"exampleFix":"// before\nreq := &vtadminpb.VTExplainRequest{Keyspace: \"ks\", Sql: q}\n// after\nreq := &vtadminpb.VExplainRequest{ClusterId: \"prod-main\", Keyspace: \"ks\", Sql: q}","handlingStrategy":"validation","validationCode":"func validateVTExplainRequest(cluster, keyspace, sql string) error {\n    if cluster == \"\" {\n        return errors.New(\"cluster ID is required\")\n    }\n    if keyspace == \"\" {\n        return errors.New(\"keyspace name is required\")\n    }\n    if sql == \"\" {\n        return errors.New(\"SQL query is required\")\n    }\n    return nil\n}","typeGuard":"func vtExplainRequestValid(req *vtadminpb.VTExplainRequest) bool {\n    return req != nil && req.Cluster != \"\" && req.Keyspace != \"\" && req.Sql != \"\"\n}","tryCatchPattern":"if !vtExplainRequestValid(req) {\n    return errors.New(\"VTExplain requires cluster, keyspace and sql; prefer VExplain instead\")\n}\nresp, err := client.VTExplain(ctx, req)","preventionTips":["Migrate to VExplain (ClusterId-based) to avoid the deprecated endpoint","Update legacy clients to populate req.Cluster if VTExplain must still be used","Track deprecation warnings and fix call sites before the endpoint is removed"],"tags":["vtadmin","deprecation","validation","vexplain"],"backgroundTag":"missing-required-request-field","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}