juicedata/juicefs · error

read worker config: %s

Error message

read worker config: %s

What it means

ReadClusterWorkerConfig reads the worker config (storage URLs + env) that the manager pipes over the worker's stdin. This error wraps any failure reading that stdin stream (io.ReadAll on a limited reader), e.g. the pipe was closed early or the reader returned an I/O error.

Source

Thrown at pkg/sync/cluster.go:414

	})
	if err != nil {
		return nil, nil, fmt.Errorf("marshal worker config: %s", err)
	}

	args := []string{host, path}
	args = append(args, workerArgs...)
	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)

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Re-run the sync and check the manager side for crashes or network drops
  2. Verify the SSH transport to workers is stable (no aggressive timeouts, keepalives enabled)
  3. Check that nothing else consumes or closes the worker's stdin (shell redirections, wrapper scripts)
  4. If persistent, inspect disk/OS-level pipe errors on the worker host

Example fix

// before (wrapper consuming stdin)
ssh worker 'somecmd | juicefs sync ...'
// after (pass manager payload via stdin untouched)
ssh worker 'juicefs sync ... --manager host:port' < config.json
Defensive patterns

Strategy: try-catch

Try / catch

src, dst, env, err := sync.ReadClusterWorkerConfig(os.Stdin)
if err != nil {
	if strings.Contains(err.Error(), "read worker config") {
		logger.Fatalf("worker stdin transport failed: %v — check manager liveness and SSH stability", err)
	}
	logger.Fatalf("worker config error: %v", err)
}

Prevention

When it happens

Trigger: The worker process's stdin pipe errors or is closed prematurely before EOF while ReadClusterWorkerConfig reads up to maxClusterWorkerConfigSize+1 bytes — e.g. manager died mid-write, SSH connection dropped, or a broken pipe on the transport.

Common situations: SSH connection to the manager drops during cluster sync startup; the manager process is killed while launching workers; stdin redirected from a file/pipe that errors or is already closed.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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