netbirdio/netbird · warning

marshal config: %w

Error message

marshal config: %w

What it means

After a successful GetConfig RPC, the response is rendered with protojson (Multiline, EmitUnpopulated). Marshal errors with valid protobuf messages are practically unreachable: protojson fails only on messages containing types it cannot represent, and GetConfigResponse is a plain config message of scalars/enums/strings produced by the daemon itself. Seeing this error indicates a serious skew, e.g. a CLI linked against an incompatible generated proto version of GetConfigResponse, or memory corruption — not a user misconfiguration.

Source

Thrown at client/cmd/debug.go:146

			log.Errorf(errCloseConnection, err)
		}
	}()

	client := proto.NewDaemonServiceClient(conn)
	resp, err := client.GetConfig(cmd.Context(), &proto.GetConfigRequest{
		ProfileName: string(activeProf.ID),
		Username:    currUser.Username,
	})
	if err != nil {
		return fmt.Errorf("failed to get config: %v", status.Convert(err).Message())
	}

	// Use protojson so well-known fields render correctly; emit defaults so
	// the operator sees every field even when zero/empty.
	m := protojson.MarshalOptions{Multiline: true, Indent: "  ", EmitUnpopulated: true}
	out, err := m.Marshal(resp)
	if err != nil {
		return fmt.Errorf("marshal config: %w", err)
	}
	cmd.Println(string(out))
	return nil
}

// debugBundle requests the daemon to create a debug bundle and prints
// the resulting local file path and, if uploaded, the uploaded file
// key. It uses the package flags (anonymize, system info, log file
// count, CLI version, optional upload URL) to configure the bundle
// request. Returns an error if the RPC fails or if the daemon reports
// an upload failure reason.
func debugBundle(cmd *cobra.Command, _ []string) error {
	anonymizeEnabled, anonymizeLevel, err := effectiveAnonymize()
	if err != nil {
		return err
	}

	conn, err := getClient(cmd)

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Rebuild or reinstall the CLI so its generated proto code matches the daemon version (make build / official package of the same release)
  2. Check netbird version vs the daemon version and align them
  3. If you are developing: regenerate protos (client/proto generate scripts) rather than mixing stale generated files
  4. If it persists with matched versions, capture the daemon-side GetConfig response (debug logs) and report it — marshalling a well-formed response should not fail
Defensive patterns

Strategy: type-guard

Validate before calling

// Guard the marshalling step so a proto skew fails loudly with context:
out, err := m.Marshal(resp)
if err != nil {
    return fmt.Errorf("marshal config (CLI/daemon proto mismatch?): %w", err)
}

Type guard

// Verify expected shape before marshalling:
if resp.GetFile() == nil && resp.GetManagementUrl() == "" {
    return errors.New("suspicious empty GetConfigResponse; proto version skew suspected")
}

Prevention

When it happens

Trigger: CLI binary built from one branch against a daemon emitting a response decoded into a mismatched generated type; a hand-modified or downgraded binary mixing generated proto versions; theoretically unsupported well-known type fields introduced into the message in the future.

Common situations: Developer mixing build artifacts (stale client/proto generated code vs newer daemon); running an unreleased CLI against an older daemon after proto changes; otherwise essentially never in the field.

Related errors


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/dbd9313b2071565e. Report an issue: GitHub.