{"record":{"id":"f7b3e3e66ac0111c","repo":"juicedata/juicefs","slug":"unmarshal-worker-config-s","errorCode":null,"errorMessage":"unmarshal worker config: %s","messagePattern":"unmarshal worker config: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/sync/cluster.go","lineNumber":421,"sourceCode":"\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\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","sourceCodeStart":403,"sourceCodeEnd":439,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/pkg/sync/cluster.go#L403-L439","documentation":"After reading and size-checking the payload, ReadClusterWorkerConfig unmarshals it as JSON into clusterWorkerConfig. This error wraps json.Unmarshal failure — the stdin payload is not valid JSON for the expected schema.","triggerScenarios":"The bytes piped to the worker's stdin are malformed or not JSON: manager/worker binary version skew with different payload formats, wrapper scripts injecting extra output into stdin, truncated payload, or feeding the worker a non-config stream.","commonSituations":"Mixed JuiceFS versions in a cluster (old manager JSON shape vs new worker); shell pipelines or SSH wrappers that alter stdin; users manually running a worker command and piping the wrong data.","solutions":["Confirm the manager and worker run the same JuiceFS version (juicefs version on all nodes)","Run the worker command directly without wrapper scripts/pipelines so stdin carries only the manager's JSON payload","Dump the stdin payload (hexdump the input in a test harness) to inspect corruption or truncation","Check the wrapped error text (%s) for the JSON offset/syntax detail"],"exampleFix":"// before\nssh worker 'cat extra.txt; juicefs sync ... --manager addr' < payload\n// after\nssh worker 'juicefs sync ... --manager addr' < payload","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"src, dst, env, err := sync.ReadClusterWorkerConfig(os.Stdin)\nif err != nil {\n\tif strings.Contains(err.Error(), \"unmarshal worker config\") {\n\tlogger.Fatalf(\"invalid worker config JSON: %v — check binary version parity and stdin wrappers\", err)\n}\nlogger.Fatalf(\"worker config error: %v\", err)\n}","preventionTips":["Run identical JuiceFS versions on manager and all workers","Never wrap the worker command in pipelines that add bytes to stdin","Validate payload JSON manually when testing workers"],"tags":["sync","cluster","json","stdin"],"backgroundTag":"json-unmarshal-failed","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"}