gastownhall/beads · error

reading %s: %w

Error message

reading %s: %w

What it means

LoadProxiedServerClientInfo failed to read the proxied server client info JSON file and wraps the os.ReadFile error. A missing file is treated as "no info" (returns nil, nil), so this error means the file exists but could not be read — permissions, I/O error, or it is a directory. It surfaces when the tool tries to load connection info for a proxied Dolt server.

Source

Thrown at internal/configfile/proxied_server_client_info.go:33

	ConfigPath  string              `json:"config_path,omitempty"`
	LogPath     string              `json:"log_path,omitempty"`
	Port        int                 `json:"port,omitempty"`
	IdleTimeout time.Duration       `json:"idle_timeout,omitempty"`
	External    *ExternalDoltConfig `json:"external,omitempty"`
}

func ProxiedServerClientInfoPath(beadsDir string) string {
	return filepath.Join(beadsDir, ProxiedServerClientInfoFileName)
}

func LoadProxiedServerClientInfo(beadsDir string) (*ProxiedServerClientInfo, error) {
	path := ProxiedServerClientInfoPath(beadsDir)
	data, err := os.ReadFile(path) // #nosec G304 - controlled path
	if os.IsNotExist(err) {
		return nil, nil
	}
	if err != nil {
		return nil, fmt.Errorf("reading %s: %w", ProxiedServerClientInfoFileName, err)
	}
	var info ProxiedServerClientInfo
	if err := json.Unmarshal(data, &info); err != nil {
		return nil, fmt.Errorf("parsing %s: %w", ProxiedServerClientInfoFileName, err)
	}
	return &info, nil
}

func SaveProxiedServerClientInfo(beadsDir string, info *ProxiedServerClientInfo) error {
	if info == nil {
		info = &ProxiedServerClientInfo{}
	}
	data, err := json.MarshalIndent(info, "", "  ")
	if err != nil {
		return fmt.Errorf("marshaling %s: %w", ProxiedServerClientInfoFileName, err)
	}
	path := ProxiedServerClientInfoPath(beadsDir)
	if err := os.WriteFile(path, data, 0o600); err != nil {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check ownership/permissions: ls -l .beads/proxied_server_client_info.json; chown/chmod so the current user can read it, or delete it and let the server re-create it.
  2. If the path is a directory, remove it and restart the proxied server to regenerate the file.
  3. Re-run the command that starts/registers the proxied server so SaveProxiedServerClientInfo rewrites the file.
  4. Inspect the wrapped %w error for the exact OS reason (EACCES, EISDIR, EIO) and address accordingly.

Example fix

// before
# ls -l .beads/proxied_server_client_info.json -> owned by root
// after
# sudo chown $USER .beads/proxied_server_client_info.json
Defensive patterns

Strategy: try-catch

Validate before calling

info, err := configfile.LoadProxiedServerClientInfo(beadsDir)
if err != nil {
    if perr, ok := err.(*fs.PathError); ok && perr.Err == syscall.EACCES {
        log.Fatalf("cannot read proxied server info (permissions): %v", perr)
    }
    return err
}

Try / catch

info, err := configfile.LoadProxiedServerClientInfo(beadsDir)
if err != nil {
    var perr *fs.PathError
    if errors.As(err, &perr) {
        log.Printf("proxied server info unreadable (%v); attempting regeneration", perr.Err)
        os.Remove(filepath.Join(beadsDir, configfile.ProxiedServerClientInfoFileName))
    }
    return err
}

Prevention

When it happens

Trigger: Calling LoadProxiedServerClientInfo when ProxiedServerClientInfoFileName inside the beads dir exists but is unreadable by the current user, is a directory, or the filesystem returns an I/O error.

Common situations: File created by a different user (e.g. root ran bd once, then a normal user); stale file replaced by a directory; NFS/network filesystem hiccup; restrictive umask or sandboxed environment blocking read.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/7612e1eef84f3a1e. Report an issue: GitHub.