gastownhall/beads · error

marshaling %s: %w

Error message

marshaling %s: %w

What it means

SaveProxiedServerClientInfo serializes the ProxiedServerClientInfo struct to JSON before writing it to the .beads directory. This error wraps any json.MarshalIndent failure, prefixed with the sidecar filename so the developer knows which file failed to build. Marshaling of this plain struct should essentially never fail in practice, so this is a defensive wrapper.

Source

Thrown at internal/configfile/proxied_server_client_info.go:48

		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 {
		return fmt.Errorf("writing %s: %w", ProxiedServerClientInfoFileName, err)
	}
	return nil
}

func resolveSidecarPath(beadsDir, p string) string {
	if p == "" {
		return ""
	}
	if filepath.IsAbs(p) {
		return p
	}
	return filepath.Join(beadsDir, p)
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped inner error (%w) to identify the field that failed to marshal.
  2. Check for recent changes to the ProxiedServerClientInfo struct — remove or fix fields with unsupported types or broken custom MarshalJSON methods.
  3. Verify no custom MarshalJSON on the struct returns non-nil errors.

Example fix

// before
type ProxiedServerClientInfo struct {
    Conn func() net.Conn `json:"conn"`
}
// after
type ProxiedServerClientInfo struct {
    Addr string `json:"addr"`
}
Defensive patterns

Strategy: try-catch

Validate before calling

if info != nil {
    if _, err := json.Marshal(info); err != nil {
        // reject/fix info before calling SaveProxiedServerClientInfo
    }
}

Try / catch

if err := configfile.SaveProxiedServerClientInfo(beadsDir, info); err != nil {
    var perr *json.UnsupportedTypeError
    if errors.As(err, &perr) {
        log.Fatalf("unsupported field type %v in client info", perr.Type)
    }
    return fmt.Errorf("saving proxied server client info: %w", err)
}

Prevention

When it happens

Trigger: Calling SaveProxiedServerClientInfo with an *ProxiedServerClientInfo that json.Marshal cannot serialize — practically only possible with unsupported types (channels, funcs, cycles) injected via custom MarshalJSON on the struct's fields.

Common situations: A new field was added to ProxiedServerClientInfo with a type that fails marshaling, or a custom MarshalJSON implementation returns an error; seen during development, not in normal operation.

Related errors


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