Skip to content

fix: encode non-addressable values with pointer receiver methods#388

Open
Yanhu007 wants to merge 1 commit into
vmihailenco:v5from
Yanhu007:fix/encode-non-addressable-pointer-receiver
Open

fix: encode non-addressable values with pointer receiver methods#388
Yanhu007 wants to merge 1 commit into
vmihailenco:v5from
Yanhu007:fix/encode-non-addressable-pointer-receiver

Conversation

@Yanhu007
Copy link
Copy Markdown

Fixes #374

Problem

When encoding a value type that implements CustomEncoder, encoding.BinaryMarshaler, or encoding.TextMarshaler via pointer receivers, the encoder returns:

msgpack: Encode(non-addressable main.Operation)

This happens because the encoder calls v.Addr() which requires the value to be addressable — but values returned from functions, stored in interfaces, or used directly (not via pointer) are not addressable.

Fix

In all four *Addr encoder functions, when v.CanAddr() is false, allocate a temporary addressable copy via reflect.New + Set, then proceed normally. This matches how encoding/json handles the same situation.

if !v.CanAddr() {
    vp := reflect.New(v.Type())
    vp.Elem().Set(v)
    v = vp.Elem()
}

Testing

All existing tests pass.

When encoding a value type that implements CustomEncoder,
encoding.BinaryMarshaler, or encoding.TextMarshaler via pointer
receivers, the encoder returns an unhelpful error if the value
is not addressable (e.g. returned directly from a function or
stored in an interface).

Instead of returning an error, allocate a temporary addressable
copy of the value and encode through that. This matches how
encoding/json handles the same situation.

Fixes vmihailenco#374
@xe-nvdk
Copy link
Copy Markdown

xe-nvdk commented Apr 14, 2026

Hi @Yanhu007, solid fix. This repo has been unmaintained for ~3 years so PRs have been sitting without review.

We maintain an active fork at github.com/Basekick-Labs/msgpack (v6) where we've already addressed this via an ensureAddr helper in encode_value.go that allocates an addressable copy when the value isn't already addressable — same approach as yours:

if v.CanAddr() {
    return v.Addr()
}
// allocate addressable copy and set
vp := reflect.New(v.Type())
vp.Elem().Set(v)
return vp

If you're looking for an actively maintained home for this work, PRs to the fork are welcome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Types with pointer receivers that are not pointers cause do not encode

2 participants