juicedata/juicefs · error

worker config is missing source or destination

Error message

worker config is missing source or destination

What it means

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.

Source

Thrown at pkg/sync/cluster.go:424

	}
	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)
				return
			}
			rpath := filepath.Join("/tmp", filepath.Base(path))
			cmd := exec.Command("rsync", "-a", "-e", "ssh -o StrictHostKeyChecking=no -o PasswordAuthentication=no", path, host+":"+rpath)

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Verify the manager's sync invocation includes both non-empty Source and Destination arguments
  2. Check manager-side logs for how clusterSource/clusterDestination were derived from the Config
  3. Ensure all nodes run compatible JuiceFS versions with matching clusterWorkerConfig field names
  4. If crafting test payloads, include both "source" and "destination" fields

Example fix

// before
{"env":{}} // worker rejects
// after
{"source":"s3://bucket/a","destination":"s3://bucket/b","env":{}}
Defensive patterns

Strategy: validation

Validate before calling

var cfg struct {
	Source      string            `json:"source"`
	Destination string            `json:"destination"`
	Env         map[string]string `json:"env"`
}
if err := json.Unmarshal(payload, &cfg); err == nil && (cfg.Source == "" || cfg.Destination == "") {
	return fmt.Errorf("worker config is missing source or destination")
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06). Data as JSON: /api/errors/6bba1f42cf149230. Report an issue: GitHub.