juicedata/juicefs · error
unmarshal worker config: %s
Error message
unmarshal worker config: %s
What it means
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.
Source
Thrown at pkg/sync/cluster.go:421
args = append(args, "--manager", address)
if !config.Verbose && !config.Quiet {
args = append(args, "-q")
}
return shellescape.EscapeArgs(args), payload, nil
}
// ReadClusterWorkerConfig reads storage URLs and environment variables from worker stdin.
func ReadClusterWorkerConfig(r io.Reader) (string, string, map[string]string, error) {
data, err := io.ReadAll(io.LimitReader(r, maxClusterWorkerConfigSize+1))
if err != nil {
return "", "", nil, fmt.Errorf("read worker config: %s", err)
}
if len(data) > maxClusterWorkerConfigSize {
return "", "", nil, fmt.Errorf("worker config is too large")
}
var config clusterWorkerConfig
if err := json.Unmarshal(data, &config); err != nil {
return "", "", nil, fmt.Errorf("unmarshal worker config: %s", err)
}
if config.Source == "" || config.Destination == "" {
return "", "", nil, fmt.Errorf("worker config is missing source or destination")
}
return config.Source, config.Destination, config.Env, nil
}
func launchWorker(address string, config *Config, wg *sync.WaitGroup) {
workers := strings.Split(strings.Join(config.Workers, ","), ",")
for _, host := range workers {
wg.Add(1)
go func(host string) {
defer wg.Done()
// copy
path, err := findSelfPath()
if err != nil {
logger.Errorf("find self path: %s", err)
returnView on GitHub (pinned to c9a67b23e8)
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
Example fix
// before ssh worker 'cat extra.txt; juicefs sync ... --manager addr' < payload // after ssh worker 'juicefs sync ... --manager addr' < payload
Defensive patterns
Strategy: try-catch
Try / catch
src, dst, env, err := sync.ReadClusterWorkerConfig(os.Stdin)
if err != nil {
if strings.Contains(err.Error(), "unmarshal worker config") {
logger.Fatalf("invalid worker config JSON: %v — check binary version parity and stdin wrappers", err)
}
logger.Fatalf("worker config error: %v", err)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
- marshal worker config: %s
- read worker config: %s
- worker config is too large
- worker config is missing source or destination
- can't locate source or destination in command arguments
AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06).
Data as JSON: /api/errors/f7b3e3e66ac0111c.
Report an issue: GitHub.