{"record":{"id":"d392ea88425e06e9","repo":"vitessio/vitess","slug":"at-least-one-table-must-be-specified","errorCode":null,"errorMessage":"at least one table must be specified","messagePattern":"at least one table must be specified","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtctl/workflow/lookup_vindex.go","lineNumber":354,"sourceCode":"\n\tignoreNulls := false\n\tif ignoreNullsStr, ok := vindex.Params[\"ignore_nulls\"]; ok {\n\t\t// This mirrors the behavior of vindexes.boolFromMap().\n\t\tswitch ignoreNullsStr {\n\t\tcase \"true\":\n\t\t\tignoreNulls = true\n\t\tcase \"false\":\n\t\t\tignoreNulls = false\n\t\tdefault:\n\t\t\treturn nil,\n\t\t\t\tvterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, \"ignore_nulls (%s) value must be 'true' or 'false'\",\n\t\t\t\t\tignoreNullsStr)\n\t\t}\n\t}\n\n\t// Validate input table.\n\tif len(tables) < 1 {\n\t\treturn nil, errors.New(\"at least one table must be specified\")\n\t}\n\n\treturn &vindexInfo{\n\t\tname:            vindexName,\n\t\ttargetKeyspace:  targetKeyspace,\n\t\ttargetTableName: targetTableName,\n\t\tfromCols:        vindexFromCols,\n\t\ttoCol:           vindexToCol,\n\t\tignoreNulls:     ignoreNulls,\n\t}, nil\n}\n\nfunc (lv *lookupVindex) getTargetAndSourceVSchema(ctx context.Context, sourceKeyspace, targetKeyspace string) (sourceVSchema, targetVSchema *topo.KeyspaceVSchemaInfo, err error) {\n\tsourceVSchema, err = lv.ts.GetVSchema(ctx, sourceKeyspace)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tif sourceVSchema.Vindexes == nil {","sourceCodeStart":336,"sourceCodeEnd":372,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtctl/workflow/lookup_vindex.go#L336-L372","documentation":"validateAndGetVindexInfo validates user-supplied input for CreateLookupVindex and requires at least one source table. When the \"tables\" input resolves to an empty list, it returns this error because a lookup vindex must be built against at least one table.","triggerScenarios":"Invoking CreateLookupVindex (via vtctldclient or workflow package) with a table spec that yields zero tables — e.g. omitting the tables argument, passing an empty object/array, or a spec the parser resolves to no tables.","commonSituations":"Empty or malformed vschema JSON file passed on the command line; script variable holding table names expanding to empty; forgetting the table key in the Vindex spec.","solutions":["Include at least one table in the vindex spec's tables before creating the lookup vindex","Verify the vschema JSON file is non-empty and well-formed","Check shell/script variables that supply table names aren't empty"],"exampleFix":"// before\n{\"vindexes\": {\"lv\": {\"type\": \"consistent_lookup_unique\"}}}  // no tables\n// after\n{\"vindexes\": {\"lv\": {\"type\": \"consistent_lookup_unique\"}}, \"tables\": {\"user\": {\"column_vindexes\": [{\"column\": \"id\", \"name\": \"lv\"}]}}}","handlingStrategy":"validation","validationCode":"if len(tables) == 0 {\n    return fmt.Errorf(\"CreateLookupVindex requires at least one table in the spec\")\n}","typeGuard":"func hasTables(tables []string) bool { return len(tables) > 0 }","tryCatchPattern":"if err := createLookupVindex(...); err != nil {\n    if strings.Contains(err.Error(), \"at least one table must be specified\") {\n        return fmt.Errorf(\"check the tables argument/vschema JSON: %w\", err)\n    }\n    return err\n}","preventionTips":["Validate the vschema JSON is non-empty and parses before invoking","Assert table-name shell variables are non-empty","Include at least one table entry in every vindex spec"],"tags":["vindex","vschema","lookup-vindex","validation"],"backgroundTag":"missing-required-argument","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}