{"record":{"id":"e0e913569ac5a848","repo":"vitessio/vitess","slug":"invalid-format-for-external-source-cluster-s","errorCode":null,"errorMessage":"invalid format for external source cluster: %s","messagePattern":"invalid format for external source cluster: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtctl/vtctl.go","lineNumber":2068,"sourceCode":"\tvReplicationWorkflowActionCreate         = \"create\"\n\tvReplicationWorkflowActionSwitchTraffic  = \"switchtraffic\"\n\tvReplicationWorkflowActionReverseTraffic = \"reversetraffic\"\n\tvReplicationWorkflowActionComplete       = \"complete\"\n\tvReplicationWorkflowActionCancel         = \"cancel\"\n\tvReplicationWorkflowActionShow           = \"show\"\n\tvReplicationWorkflowActionProgress       = \"progress\"\n\tvReplicationWorkflowActionGetState       = \"getstate\"\n)\n\nfunc commandMigrate(ctx context.Context, wr *wrangler.Wrangler, subFlags *pflag.FlagSet, args []string) error {\n\treturn commandVReplicationWorkflow(ctx, wr, subFlags, args, wrangler.MigrateWorkflow)\n}\n\n// getSourceKeyspace expects a keyspace of the form \"externalClusterName.keyspaceName\" and returns the components\nfunc getSourceKeyspace(clusterKeyspace string) (clusterName string, sourceKeyspace string, err error) {\n\tsplits := strings.Split(clusterKeyspace, \".\")\n\tif len(splits) != 2 {\n\t\treturn \"\", \"\", fmt.Errorf(\"invalid format for external source cluster: %s\", clusterKeyspace)\n\t}\n\treturn splits[0], splits[1], nil\n}\n\n// commandVReplicationWorkflow is the common entry point for MoveTables/Reshard/Migrate workflows\n// FIXME: this function needs a refactor. Also validations for params should to be done per workflow type\nfunc commandVReplicationWorkflow(ctx context.Context, wr *wrangler.Wrangler, subFlags *pflag.FlagSet, args []string,\n\tworkflowType wrangler.VReplicationWorkflowType,\n) error {\n\tconst defaultWaitTime = time.Duration(30 * time.Second)\n\t// for backward compatibility we default the lag to match the timeout for switching primary traffic\n\t// this should probably be much smaller so that target and source are almost in sync before switching traffic\n\tconst defaultMaxReplicationLagAllowed = defaultWaitTime\n\n\tcells := subFlags.String(\"cells\", \"\", \"Cell(s) or CellAlias(es) (comma-separated) to replicate from.\")\n\ttabletTypesStr := subFlags.String(\"tablet_types\", \"in_order:REPLICA,PRIMARY\", \"Source tablet types to replicate from (e.g. PRIMARY, REPLICA, RDONLY). Note: SwitchTraffic overrides this default and uses in_order:RDONLY,REPLICA,PRIMARY to switch all traffic by default.\")\n\tdryRun := subFlags.Bool(\"dry_run\", false, \"Does a dry run of SwitchTraffic and only reports the actions to be taken. --dry_run is only supported for SwitchTraffic, ReverseTraffic and Complete.\")\n\ttimeout := subFlags.Duration(\"timeout\", defaultWaitTime, \"Specifies the maximum time to wait, in seconds, for vreplication to catch up on primary migrations. The migration will be cancelled on a timeout. --timeout is only supported for SwitchTraffic and ReverseTraffic.\")","sourceCodeStart":2050,"sourceCodeEnd":2086,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtctl/vtctl.go#L2050-L2086","documentation":"getSourceKeyspace parses an external cluster source string expected in the form 'externalClusterName.keyspaceName' (exactly one dot separator). This error is returned when the argument does not split into exactly two components, so the cluster name and source keyspace cannot be determined.","triggerScenarios":"Running commandVReplicationWorkflow-backed commands (MoveTables/Migrate with an external source) where the --source argument or keyspace param lacks the 'cluster.keyspace' format — e.g. zero dots ('commerce') or multiple dots ('c1.ks.extra').","commonSituations":"Forgetting to prefix the keyspace with the external cluster name during VReplication migrations; copying an internal keyspace name into a flag that requires the external form; typos adding a second dot.","solutions":["Pass the value as `<externalClusterName>.<keyspaceName>` with exactly one dot","Verify the external cluster name is registered in the topo (`ExternalCluster` config)","Check the string for stray dots or extra components and fix them","Confirm the flag you're using expects the external form (internal keyspaces don't need the prefix)"],"exampleFix":"// before\nvtctl MoveTables -source=commerce customer  # missing cluster prefix\n// after\nvtctl MoveTables -source=ext1.commerce customer\n","handlingStrategy":"validation","validationCode":"validate_external_source() {\n  local n=$(echo \"$1\" | awk -F. '{print NF-1}')\n  [[ \"$n\" -eq 1 ]] || { echo \"expected <cluster>.<keyspace>, got: $1\"; return 1; }\n}\nvalidate_external_source \"$SOURCE\" || exit 1","typeGuard":null,"tryCatchPattern":"if err := runVtctl(\"MoveTables\", \"--source=\"+src, ...); err != nil {\n    if strings.Contains(err.Error(), \"invalid format for external source cluster\") {\n        // re-format as cluster.keyspace and retry\n    }\n}","preventionTips":["Always prefix external-source keyspaces with the registered external cluster name","Keep cluster.keyspace pairs in config, not ad-hoc strings","Validate the single-dot format in wrapper scripts","Distinguish internal workflows (no prefix) from external Migrate/MoveTables (prefix required)"],"tags":["vtctl","vreplication","movetables","parsing"],"backgroundTag":"invalid-external-source-format","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}