{"record":{"id":"f58ed6fc203dd50b","repo":"juicedata/juicefs","slug":"can-t-locate-source-or-destination-in-command-argu","errorCode":null,"errorMessage":"can't locate source or destination in command arguments","messagePattern":"can't locate source or destination in command arguments","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/sync/cluster.go","lineNumber":389,"sourceCode":"\t}\n\treturn \"\", fmt.Errorf(\"can't find path for %s\", program)\n}\n\nfunc prepareWorkerCommand(host, address, path string, config *Config) ([]string, []byte, error) {\n\tworkerArgs := append([]string(nil), os.Args[1:]...)\n\tvar foundSource, foundDestination bool\n\tfor i, arg := range workerArgs {\n\t\tif arg == config.clusterSource {\n\t\t\tworkerArgs[i] = utils.RemovePassword(config.clusterSource)\n\t\t\tfoundSource = true\n\t\t}\n\t\tif arg == config.clusterDestination {\n\t\t\tworkerArgs[i] = utils.RemovePassword(config.clusterDestination)\n\t\t\tfoundDestination = true\n\t\t}\n\t}\n\tif !foundSource || !foundDestination {\n\t\treturn nil, nil, fmt.Errorf(\"can't locate source or destination in command arguments\")\n\t}\n\n\tpayload, err := json.Marshal(clusterWorkerConfig{\n\t\tSource:      config.clusterSource,\n\t\tDestination: config.clusterDestination,\n\t\tEnv:         config.Env,\n\t})\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"marshal worker config: %s\", err)\n\t}\n\n\targs := []string{host, path}\n\targs = append(args, workerArgs...)\n\targs = append(args, \"--manager\", address)\n\tif !config.Verbose && !config.Quiet {\n\t\targs = append(args, \"-q\")\n\t}\n\treturn shellescape.EscapeArgs(args), payload, nil","sourceCodeStart":371,"sourceCodeEnd":407,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/pkg/sync/cluster.go#L371-L407","documentation":"prepareWorkerCommand builds the SSH command line for a distributed-sync worker by scanning the manager's own os.Args for the source and destination storage URLs so they can be redacted (passwords removed) in the worker argv. If neither (or either) of the configured clusterSource/clusterDestination strings appears verbatim in the process arguments, the manager refuses to launch the worker and throws this error rather than leaking credentials or launching a worker with wrong storage targets.","triggerScenarios":"juicefs sync --cluster is run and the source or destination URL passed on the command line differs from config.clusterSource/clusterDestination — e.g. the URLs were normalized after flag parsing (path cleanup, scheme canonicalization), aliases/relpaths resolved, or flags set programmatically rather than via argv.","commonSituations":"Launching cluster sync programmatically (SDK/tests) with a Config whose Source/Destination never appear in os.Args; passing URLs that get rewritten (trailing slashes, escaped chars); running via a wrapper that rewrites argv; source or destination given as a local path that was converted to a canonical URI.","solutions":["Ensure the exact source and destination URL strings given to Sync appear verbatim in the process command-line arguments (os.Args) — pass them as CLI flags, not only in the Config struct","Check for normalization differences: print config.clusterSource/clusterDestination and compare to os.Args to find canonicalization (scheme case, trailing slash, percent-encoding) mismatches","If invoking sync programmatically, run cluster sync via the CLI entrypoint so argv contains both URLs, or patch the code to populate workerArgs from config instead of os.Args"],"exampleFix":"// before (programmatic call, argv lacks URLs)\ncfg := &sync.Config{Source: \"s3://bucket/a\", Destination: \"s3://bucket/b\", Cluster: \"...\"}\nsync.Sync(cfg) // -> can't locate source or destination in command arguments\n\n// after (run through CLI so argv contains both URLs)\njuicefs sync s3://bucket/a s3://bucket/b --cluster worker1,worker2","handlingStrategy":"validation","validationCode":"for _, arg := range os.Args[1:] {\n\tif arg == cfg.Source {\n\t\tfoundSrc = true\n\t}\n\tif arg == cfg.Destination {\n\t\tfoundDst = true\n\t}\n}\nif !foundSrc || !foundDst {\n\treturn fmt.Errorf(\"source %q / destination %q must appear verbatim in command args for cluster sync\", cfg.Source, cfg.Destination)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always launch cluster sync via the juicefs sync CLI so source/destination are present in os.Args","Avoid post-parsing normalization that changes the URL strings away from what was passed on the command line","Log os.Args and the resolved clusterSource/clusterDestination when debugging cluster launch failures"],"tags":["sync","cluster","argv","config"],"backgroundTag":"missing-required-argument","analyzedSha":"c9a67b23e8e08ec23ec331aa6f1675e2319e921c","analyzedAt":"2026-09-06T17:55:48.476Z","contentChangedAt":"2026-09-06T17:55:48.476Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}