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
- Rebuild or reinstall the CLI so its generated proto code matches the daemon version (make build / official package of the same release)
- Check netbird version vs the daemon version and align them
- If you are developing: regenerate protos (client/proto generate scripts) rather than mixing stale generated files
- 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
- Build CLI and daemon from the same commit or release package
- Regenerate protos with the checked-in generate scripts, never mix generated files across branches
- Treat this error as a build-integration smell, not a runtime condition
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
- readiness check: unexpected daemon status %q
- startup check: no full status available
- jwt token is required
- job not implemented
- invalid duration
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/dbd9313b2071565e.
Report an issue: GitHub.