{"record":{"id":"6bba1f42cf149230","repo":"juicedata/juicefs","slug":"worker-config-is-missing-source-or-destination","errorCode":null,"errorMessage":"worker config is missing source or destination","messagePattern":"worker config is missing source or destination","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/sync/cluster.go","lineNumber":424,"sourceCode":"\t}\n\treturn shellescape.EscapeArgs(args), payload, nil\n}\n\n// ReadClusterWorkerConfig reads storage URLs and environment variables from worker stdin.\nfunc ReadClusterWorkerConfig(r io.Reader) (string, string, map[string]string, error) {\n\tdata, err := io.ReadAll(io.LimitReader(r, maxClusterWorkerConfigSize+1))\n\tif err != nil {\n\t\treturn \"\", \"\", nil, fmt.Errorf(\"read worker config: %s\", err)\n\t}\n\tif len(data) > maxClusterWorkerConfigSize {\n\t\treturn \"\", \"\", nil, fmt.Errorf(\"worker config is too large\")\n\t}\n\tvar config clusterWorkerConfig\n\tif err := json.Unmarshal(data, &config); err != nil {\n\t\treturn \"\", \"\", nil, fmt.Errorf(\"unmarshal worker config: %s\", err)\n\t}\n\tif config.Source == \"\" || config.Destination == \"\" {\n\t\treturn \"\", \"\", nil, fmt.Errorf(\"worker config is missing source or destination\")\n\t}\n\treturn config.Source, config.Destination, config.Env, nil\n}\n\nfunc launchWorker(address string, config *Config, wg *sync.WaitGroup) {\n\tworkers := strings.Split(strings.Join(config.Workers, \",\"), \",\")\n\tfor _, host := range workers {\n\t\twg.Add(1)\n\t\tgo func(host string) {\n\t\t\tdefer wg.Done()\n\t\t\t// copy\n\t\t\tpath, err := findSelfPath()\n\t\t\tif err != nil {\n\t\t\t\tlogger.Errorf(\"find self path: %s\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trpath := filepath.Join(\"/tmp\", filepath.Base(path))\n\t\t\tcmd := exec.Command(\"rsync\", \"-a\", \"-e\", \"ssh -o StrictHostKeyChecking=no -o PasswordAuthentication=no\", path, host+\":\"+rpath)","sourceCodeStart":406,"sourceCodeEnd":442,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/pkg/sync/cluster.go#L406-L442","documentation":"After a successful JSON unmarshal, ReadClusterWorkerConfig validates that both Source and Destination are non-empty. If either is missing from the worker config payload it throws this error, since a worker cannot know what to sync. This guards against a manager sending a truncated or misconfigured payload.","triggerScenarios":"A manager marshaled clusterWorkerConfig with empty Source or Destination (config.clusterSource/clusterDestination empty because Sync was called with missing/normalized-away URLs), or a hand-crafted/hijacked JSON payload with fields omitted (empty strings).","commonSituations":"Programmatic Config built without Source/Destination but with a Cluster specified; JSON produced by a different (incompatible) manager version using different field names; users manually piping test JSON lacking fields.","solutions":["Verify the manager's sync invocation includes both non-empty Source and Destination arguments","Check manager-side logs for how clusterSource/clusterDestination were derived from the Config","Ensure all nodes run compatible JuiceFS versions with matching clusterWorkerConfig field names","If crafting test payloads, include both \"source\" and \"destination\" fields"],"exampleFix":"// before\n{\"env\":{}} // worker rejects\n// after\n{\"source\":\"s3://bucket/a\",\"destination\":\"s3://bucket/b\",\"env\":{}}","handlingStrategy":"validation","validationCode":"var cfg struct {\n\tSource      string            `json:\"source\"`\n\tDestination string            `json:\"destination\"`\n\tEnv         map[string]string `json:\"env\"`\n}\nif err := json.Unmarshal(payload, &cfg); err == nil && (cfg.Source == \"\" || cfg.Destination == \"\") {\n\treturn fmt.Errorf(\"worker config is missing source or destination\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Verify Source and Destination are non-empty before configuring a cluster sync","Include both fields when hand-crafting worker test payloads","Keep worker/manager payload schemas in version lockstep"],"tags":["sync","cluster","validation","stdin"],"backgroundTag":"empty-required-field","analyzedSha":"c9a67b23e8e08ec23ec331aa6f1675e2319e921c","analyzedAt":"2026-09-06T17:55:48.476Z","contentChangedAt":"2026-09-06T17:55:48.476Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}