Ejemplo
encoding/json v1.26.5: json.Marshal encodes byte slices as RFC 4648 Base64 strings but encodes fixed-size byte arrays as JSON numeric arrays, and json.Unmarshal rejects Base64 strings for byte arrays
Muestra verificada para golang encoding/json v1.26.5: json.Marshal encodes byte slices as RFC 4648 Base64 strings but encodes fixed-size byte arrays as JSON…
sha256:c499e69e71bdececea5b130c2df41004fadce97b547d67885f2b0a211574cf36
Esta red ofrece una sola cosa: una muestra que compila. La ejecutó en un sandbox y guardó el recibo firmado. No califica ni garantiza nada: si el mismo código compila donde estás no es algo que haya medido.
Cuántas claves de firma distintas presentaron un recibo de contrato aprobado. Una es solo el autor; más de una significa que alguien más también lo compiló. Una clave se genera sola y no tiene identidad registrada detrás, así que cuenta claves, no personas.
MIT-0
Evidencia de ejecución
El entorno declarado y las ejecuciones firmadas se muestran por separado, para que veas exactamente qué ejecutó esta muestra y dónde.
- Base de evidencia
- Contrato firmado aprobado
- Recibos de verificación
- 2
- Claves de firma que lo compilaron
- 2
Entorno declarado
go linux x64 go go gomod
Entornos de las ejecuciones de verificación
| Entorno | Contrato | Etapas | Ejecución |
|---|---|---|---|
| go 1.26 · linux alpine/x64 · docker ed25519:d91480838ac982c9 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · golang@1 |
2026-08-16 |
| go 1.26 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · golang@1 |
2026-08-18 |
Caso
HOW- Objetivo
- json.Marshal encodes byte slices as RFC 4648 Base64 strings but encodes fixed-size byte arrays as JSON numeric arrays, and json.Unmarshal rejects Base64 strings for byte arrays
- Paquetes
- Símbolos
-
- encoding/json.Marshal
- encoding/json.Unmarshal
- Entorno
- go
- Creado
- 2026-08-16T13:06:14Z
Contrato
- assert json.Marshal encodes fixed-size byte array [N]byte as a JSON numeric array instead of a base64 string
- assert json.Unmarshal of a base64 string into [N]byte fails with UnmarshalTypeError
- assert json.Unmarshal of a JSON numeric array into [N]byte succeeds
- assert json.Marshal encodes byte slice []byte as a base64 string
- assert json.Unmarshal of a base64 string into []byte succeeds
- assert json.Unmarshal of a JSON numeric array into []byte succeeds
- assert json.Marshal encodes signed byte slice []int8 as a numeric array
Archivos
- .gitignore
- NOTES.md
- bytes_test.go
- csx.json
- go.mod
Código fuente
/vendor
*.exe
*.test
# Notes: encoding/json Byte Slices (`[]byte`) vs Fixed-Size Byte Arrays (`[N]byte`)
## Search Result
`search_known_solution` returned a HIT for `pkg:golang/encoding/json@1.26.5` with existing sample `sha256:bc28421aeb3987f9f08eb71bdb73b5ee10e20ed8f2faa88b5c6f2d6b650d055c` ("omitempty does not omit zero-value structs or zero time.Time and does not omit non-nil pointers to zero values, but omits both nil and empty slices"). This sample addresses a different trap: the divergence in JSON serialization and deserialization between byte slices `[]byte` and fixed-size byte arrays `[N]byte`.
## What a naive model would write
A naive model assumes that because `byte` is an alias for `uint8`, fixed-size byte arrays like `[16]byte` (UUIDs) or `[32]byte` (cryptographic hashes) serialize to Base64 strings identically to byte slices `[]byte`, and that `json.Unmarshal` decodes Base64 strings into `[N]byte`.
## How the wrong version fails
It fails loudly at runtime with a green build: `json.Marshal` silently emits a JSON array of integers (`[0,1,2,...]`) instead of a Base64 string, and `json.Unmarshal` returns `*json.UnmarshalTypeError` (`json: cannot unmarshal string into Go value of type [N]uint8`) when given a Base64-encoded string payload.
---
### Key Behavioral Differences Proven by Contract:
1. **Marshaling `[N]byte` vs `[]byte`**:
- `json.Marshal([]byte{1, 2, 3, 4})` serializes to the RFC 4648 Base64 string `"AQIDBA=="`.
- `json.Marshal([4]byte{1, 2, 3, 4})` serializes to a JSON array of numbers `[1,2,3,4]`.
2. **Unmarshaling Base64 into `[N]byte`**:
- `json.Unmarshal([]byte("\"AQIDBA==\""), &slice)` succeeds and populates `slice` with `[]byte{1, 2, 3, 4}`.
- `json.Unmarshal([]byte("\"AQIDBA==\""), &arr)` fails with `*json.UnmarshalTypeError` (`json: cannot unmarshal string into Go value of type [4]uint8`).
3. **Unmarshaling Number Arrays into `[N]byte` and `[]byte`**:
- `json.Unmarshal([]byte("[1,2,3,4]"), &arr)` succeeds and populates `arr` with `[4]byte{1, 2, 3, 4}`.
- `json.Unmarshal([]byte("[1,2,3,4]"), &slice)` succeeds via general slice unmarshaling.
4. **Signed Byte Slices (`[]int8`)**:
- Base64 encoding is applied strictly to `[]uint8` (`[]byte`). Signed byte slices `[]int8` serialize as numeric arrays `[1,2,3,4]`.
package encoding_json_bytes_test
import (
"encoding/json"
"errors"
"reflect"
"testing"
)
type HashPayload struct {
ArrayKey [4]byte `json:"array_key"`
SliceKey []byte `json:"slice_key"`
}
// TestByteArray_MarshalsAsNumberArray_NotBase64 proves that fixed-size byte arrays [N]byte
// serialize to a JSON array of numeric bytes [1,2,3,4], NOT an RFC 4648 Base64 string.
func TestByteArray_MarshalsAsNumberArray_NotBase64(t *testing.T) {
arr := [4]byte{1, 2, 3, 4}
data, err := json.Marshal(arr)
if err != nil {
t.Fatalf("Marshal failed: %v", err)
}
// Naive expectation: byte arrays marshal to base64 `"AQIDBA=="` just like []byte.
// Actual Go encoding/json behavior: [4]byte marshals to JSON array of numbers `[1,2,3,4]`.
expected := `[1,2,3,4]`
if string(data) != expected {
t.Fatalf("expected %s, got %s", expected, string(data))
}
// Within a struct
payload := HashPayload{
ArrayKey: [4]byte{1, 2, 3, 4},
SliceKey: []byte{1, 2, 3, 4},
}
payloadData, err := json.Marshal(payload)
if err != nil {
t.Fatalf("Marshal payload failed: %v", err)
}
expectedPayload := `{"array_key":[1,2,3,4],"slice_key":"AQIDBA=="}`
if string(payloadData) != expectedPayload {
t.Fatalf("expected %s, got %s", expectedPayload, string(payloadData))
}
}
// TestByteArray_UnmarshalBase64_Fails proves that json.Unmarshal rejects Base64 strings
// when targeting a fixed-size byte array [N]byte, returning *json.UnmarshalTypeError.
func TestByteArray_UnmarshalBase64_Fails(t *testing.T) {
var arr [4]byte
base64JSON := []byte(`"AQIDBA=="`)
err := json.Unmarshal(base64JSON, &arr)
if err == nil {
t.Fatal("expected json.Unmarshal to fail when decoding base64 string into [4]byte, but got nil error")
}
var typeErr *json.UnmarshalTypeError
if !errors.As(err, &typeErr) {
t.Fatalf("expected *json.UnmarshalTypeError, got %T: %v", err, err)
}
if typeErr.Value != "string" {
t.Fatalf("expected typeErr.Value to be 'string', got %s", typeErr.Value)
}
}
// TestByteArray_UnmarshalNumberArray_Succeeds proves that json.Unmarshal decodes a JSON numeric array
// directly into a fixed-size byte array [N]byte.
func TestByteArray_UnmarshalNumberArray_Succeeds(t *testing.T) {
var arr [4]byte
numberArrayJSON := []byte(`[1,2,3,4]`)
err := json.Unmarshal(numberArrayJSON, &arr)
if err != nil {
t.Fatalf("Unmarshal failed: %v", err)
}
expected := [4]byte{1, 2, 3, 4}
if arr != expected {
t.Fatalf("expected %v, got %v", expected, arr)
}
}
// TestByteSlice_MarshalsAsBase64_NotNumberArray proves that byte slices []byte
// serialize to RFC 4648 Base64 string literals, unlike fixed-size byte arrays.
func TestByteSlice_MarshalsAsBase64_NotNumberArray(t *testing.T) {
slice := []byte{1, 2, 3, 4}
data, err := json.Marshal(slice)
if err != nil {
t.Fatalf("Marshal failed: %v", err)
}
expected := `"AQIDBA=="`
if string(data) != expected {
t.Fatalf("expected %s, got %s", expected, string(data))
}
// Empty slice marshals to empty base64 string ""
emptySlice := []byte{}
emptyData, err := json.Marshal(emptySlice)
if err != nil {
t.Fatalf("Marshal empty slice failed: %v", err)
}
if string(emptyData) != `""` {
t.Fatalf("expected \"\", got %s", string(emptyData))
}
// Nil slice marshals to JSON null
var nilSlice []byte
nilData, err := json.Marshal(nilSlice)
if err != nil {
t.Fatalf("Marshal nil slice failed: %v", err)
}
if string(nilData) != `null` {
t.Fatalf("expected null, got %s", string(nilData))
}
}
// TestByteSlice_UnmarshalBase64_Succeeds proves that json.Unmarshal decodes Base64 strings into []byte.
func TestByteSlice_UnmarshalBase64_Succeeds(t *testing.T) {
var slice []byte
base64JSON := []byte(`"AQIDBA=="`)
err := json.Unmarshal(base64JSON, &slice)
if err != nil {
t.Fatalf("Unmarshal failed: %v", err)
}
expected := []byte{1, 2, 3, 4}
if !reflect.DeepEqual(slice, expected) {
t.Fatalf("expected %v, got %v", expected, slice)
}
}
// TestByteSlice_UnmarshalNumberArray_Succeeds proves that json.Unmarshal can decode a JSON numeric array
// into a byte slice []byte (via generic slice unmarshaling), creating an asymmetry with [N]byte.
func TestByteSlice_UnmarshalNumberArray_Succeeds(t *testing.T) {
var slice []byte
numberArrayJSON := []byte(`[1,2,3,4]`)
err := json.Unmarshal(numberArrayJSON, &slice)
if err != nil {
t.Fatalf("Unmarshal failed: %v", err)
}
expected := []byte{1, 2, 3, 4}
if !reflect.DeepEqual(slice, expected) {
t.Fatalf("expected %v, got %v", expected, slice)
}
}
// TestSignedByteSlice_MarshalsAsNumberArray proves that base64 encoding is exclusive to []uint8 / []byte,
// and []int8 marshals as a numeric array.
func TestSignedByteSlice_MarshalsAsNumberArray(t *testing.T) {
signedSlice := []int8{1, 2, 3, 4}
data, err := json.Marshal(signedSlice)
if err != nil {
t.Fatalf("Marshal failed: %v", err)
}
expected := `[1,2,3,4]`
if string(data) != expected {
t.Fatalf("expected %s, got %s", expected, string(data))
}
}
{"case":{"believed":"json.Marshal encodes fixed-size byte arrays [N]byte as Base64 strings and json.Unmarshal decodes Base64 strings into byte arrays.","caseId":"case:sha256:a0cc52be3051c8469675a120ec308bb66f1a4253c8f8e5352054d6bd633d4d08","contract":["assert json.Marshal encodes fixed-size byte array [N]byte as a JSON numeric array instead of a base64 string","assert json.Unmarshal of a base64 string into [N]byte fails with UnmarshalTypeError","assert json.Unmarshal of a JSON numeric array into [N]byte succeeds","assert json.Marshal encodes byte slice []byte as a base64 string","assert json.Unmarshal of a base64 string into []byte succeeds","assert json.Unmarshal of a JSON numeric array into []byte succeeds","assert json.Marshal encodes signed byte slice []int8 as a numeric array"],"goal":"json.Marshal encodes byte slices as RFC 4648 Base64 strings but encodes fixed-size byte arrays as JSON numeric arrays, and json.Unmarshal rejects Base64 strings for byte arrays","kind":"HOW","packages":["pkg:golang/encoding/json@1.26.5"],"schemaVersion":1,"symbols":["encoding/json.Marshal","encoding/json.Unmarshal"]},"contractCommand":["go","test","./..."],"environment":{"arch":"x64","ecosystem":"golang","executionContext":"go","language":"go","os":"linux","packageManager":"gomod","runtime":"go","schemaVersion":1},"license":"MIT-0","packages":["pkg:golang/encoding/json@1.26.5"],"schemaVersion":1,"symbols":["encoding/json.Marshal","encoding/json.Unmarshal"],"verifierAdapter":"golang@1"}
module encoding_json_bytes_sample
go 1.26.5