golang/go · error

wrong magic, not a Go object file

Error message

wrong magic, not a Go object file

What it means

Thrown by (*goobj.Header).Read when the first bytes of a file do not equal the gc object-file magic constant ("\x00go120ld"). The goobj package reads the export data / object index of files emitted by the gc compiler's object writer, and the magic both identifies the format and pins the on-disk version. Any byte mismatch (truncation, wrong format, version skew) aborts the parse before any block offsets are read.

Source

Thrown at src/cmd/internal/goobj/objfile.go:233

	Offsets     [NBlk]uint32
}

const Magic = "\x00go120ld"

func (h *Header) Write(w *Writer) {
	w.RawString(h.Magic)
	w.Bytes(h.Fingerprint[:])
	w.Uint32(h.Flags)
	for _, x := range h.Offsets {
		w.Uint32(x)
	}
}

func (h *Header) Read(r *Reader) error {
	b := r.BytesAt(0, len(Magic))
	h.Magic = string(b)
	if h.Magic != Magic {
		return errors.New("wrong magic, not a Go object file")
	}
	off := uint32(len(h.Magic))
	copy(h.Fingerprint[:], r.BytesAt(off, len(h.Fingerprint)))
	off += 8
	h.Flags = r.uint32At(off)
	off += 4
	for i := range h.Offsets {
		h.Offsets[i] = r.uint32At(off)
		off += 4
	}
	return nil
}

func (h *Header) Size() int {
	return len(h.Magic) + len(h.Fingerprint) + 4 + 4*len(h.Offsets)
}

// Autolib

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Verify the file is actually a gc object file: `go tool nm FILE` or `head -c8 FILE | xxd` and check it begins with the magic byte 0x00 followed by 'go120ld'.
  2. Rebuild the object with the toolchain version that matches the goobj reader (clean the build cache: `go clean -cache`).
  3. Confirm the path passed to goobj.Parse is the compiled object, not the source, archive wrapper, or linked executable.
  4. If consuming third-party objects, ensure they were produced by gc (this package does not read gccgo/GoLLVM objects).

Example fix

// before: feeding an arbitrary file to the goobj reader
f, _ := os.Open(path)
r := goobj.NewReader(f, ...) 
hdr.Read(r) // -> "wrong magic, not a Go object file"

// after: sniff the magic before parsing so the caller gets a clear signal
const Magic = "\x00go120ld"
head := make([]byte, len(Magic))
if _, err := io.ReadFull(f, head); err != nil || string(head) != Magic {
    return fmt.Errorf("%s: not a gc object file", path)
}
f.Seek(0, io.SeekStart)
hdr.Read(r)
Defensive patterns

Strategy: validation

Validate before calling

// Validate the file is a gc object before handing it to goobj.
func isGcObject(path string) bool {
    f, err := os.Open(path)
    if err != nil { return false }
    defer f.Close()
    head := make([]byte, 8) // len(goobj.Magic)
    if _, err := io.ReadFull(f, head); err != nil { return false }
    return string(head) == "\x00go120ld"
}

Type guard

// Narrow on the goobj.Read error after the fact.
func isWrongMagic(err error) bool {
    return err != nil && strings.Contains(err.Error(), "wrong magic")
}

Try / catch

if err := hdr.Read(r); err != nil {
    if strings.Contains(err.Error(), "wrong magic") {
        return fmt.Errorf("%s is not a gc object file: %w", path, err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling goobj.Parse or (*Reader) on a path whose content is not a gc '.o' object: a source file, an archive unpacked wrong, a PE/ELF executable, or an object produced by a different/newer Go whose Magic constant changed. Also fires on a zero-length or truncated file where BytesAt returns fewer than len(Magic) bytes that do not match.

Common situations: Mixing Go toolchain versions (the magic string is bumped, e.g. go120ld, across major object-format revisions), feeding a text/source file to a loader that expects an object file, or a corrupted build cache / partial write left by a killed compiler process. Often seen in CI after a Go upgrade without rebuilding dependencies.

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/fcd72e64f2626acc. Report an issue: GitHub.