Skip to content
Go Basics: Encode Fixed-Width Records with Explicit Byte Order

Go Basics: Encode Fixed-Width Records with Explicit Byte Order

October 31, 2026

Binary formats need agreed field widths and byte order. Build a small header with a two-byte version and a four-byte payload length, then decode it without depending on Go struct padding.

Prepare a scratch directory

Tested on Linux amd64 with Go 1.26.10. Install Go and make go available on PATH. You also need Bash, a text editor, and the standard mktemp, rm, and rmdir utilities. The example uses only the standard library and needs no module or external dependency.

Keep the same terminal open. Stop if setup fails, before saving the source:

start_dir="$PWD"
work_dir="$(mktemp -d)" || exit 1
cd -- "$work_dir" || exit 1

Run the example

Save this as binary-byte-order-demo.go:

package main

import (
	"encoding/binary"
	"fmt"
)

func decode(data []byte) (uint16, uint32, error) {
	if len(data) != 6 {
		return 0, 0, fmt.Errorf("header must contain six bytes")
	}
	return binary.BigEndian.Uint16(data[:2]), binary.BigEndian.Uint32(data[2:]), nil
}
func main() {
	data := make([]byte, 6)
	binary.BigEndian.PutUint16(data[:2], 3)
	binary.BigEndian.PutUint32(data[2:], 1024)
	fmt.Printf("Bytes: % x\n", data)
	version, length, err := decode(data)
	if err != nil {
		panic(err)
	}
	fmt.Printf("Version=%d length=%d\n", version, length)
	_, _, err = decode(data[:5])
	fmt.Println("Short header rejected:", err != nil)
}

Run it:

go run binary-byte-order-demo.go

Observed output:

Bytes: 00 03 00 00 04 00
Version=3 length=1024
Short header rejected: true

Read the result

Big-endian encoding writes the most significant byte first. Fixed-width unsigned integers make the on-wire layout explicit. The length guard runs before slicing or decoding; otherwise a short input can cause a panic. The invalid input is an expected test case.

Apply it carefully

A decoded length is still untrusted data. Check it against application limits before allocating or reading a payload. This decoder intentionally requires exactly one header; a stream parser should read the required number of bytes, handle truncation, and leave the payload for the next step.

The official Go reference documents the behavior used here.

Clean up

Remove the saved source, return to the starting directory, and remove the empty practice directory. go run does not leave an executable here; Go manages its build cache separately.

rm -- binary-byte-order-demo.go
cd -- "$start_dir" || exit 1
rmdir -- "$work_dir"
unset start_dir work_dir

If the directory is not empty, inspect its remaining contents before removing anything else.

Acknowledgements

This post was created with assistance from AI.

Last updated on