golang/go · error

unexpected content after code signature

Error message

unexpected content after code signature

What it means

When the linker resizes a Mach-O code signature in place, it requires the signature to be the final bytes of the output file (Apple's codesign invariant: anything after the signature superblob invalidates it). The check `sigOff+sigSz != fi.Size()` detects trailing bytes — if present, the link aborts because patching the signature would leave an unverifiable binary.

Source

Thrown at src/cmd/link/internal/ld/macho.go:1569

			}
		}
		loadOff += int64(sz)
	}

	if sigOff == 0 {
		// The C linker doesn't generate a signed binary, for some reason.
		// Skip.
		return nil
	}

	fi, err := f.Stat()
	if err != nil {
		return err
	}
	if sigOff+sigSz != fi.Size() {
		// We don't expect anything after the signature (this will invalidate
		// the signature anyway.)
		return fmt.Errorf("unexpected content after code signature")
	}

	sz := codesign.Size(sigOff, "a.out")
	if sz != sigSz {
		// Update the load command,
		var tmp [8]byte
		mf.ByteOrder.PutUint32(tmp[:4], uint32(sz))
		_, err = f.WriteAt(tmp[:4], csCmdOff+12)
		if err != nil {
			return err
		}

		// Uodate the __LINKEDIT segment.
		segSz := sigOff + sz - int64(linkeditSeg.Offset)
		mf.ByteOrder.PutUint64(tmp[:8], uint64(segSz))
		_, err = f.WriteAt(tmp[:8], linkeditOff+int64(unsafe.Offsetof(macho.Segment64{}.Memsz)))
		if err != nil {
			return err

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Ensure the Go linker runs before any external `codesign`/post-processing, not after.
  2. Delete the output binary and relink from scratch so the signature is the last thing written.
  3. Remove custom `-extldflags` that alter the output tail; use the default external linker behavior.
  4. Avoid concurrent builds writing to the same output path.

Example fix

# before: external codesign ran, then linker tried to resize sig
codesign -s MySign bin/app   # wrong order
go build -o bin/app ./...

# after: link first, sign last
go build -o bin/app ./...
codesign -s MySign bin/app
Defensive patterns

Strategy: validation

Validate before calling

# Before relinking, confirm the existing binary has no trailing bytes after the signature
if [ -f bin/app ]; then
  codesign -dv bin/app 2>&1 | grep -q 'CodeDirectory v' && echo 'binary is signed; relink from scratch instead of patching'
fi

Try / catch

# Relink cleanly on failure rather than patch a signed binary
set +e
go build -o bin/app ./...
rc=$?
set -e
if [ $rc -ne 0 ]; then
  rm -f bin/app
  go build -o bin/app ./...
fi

Prevention

When it happens

Trigger: The combine-DWARF or codesign-update flow running on a binary already modified by an external tool (`codesign`, `dsymutil`, a custom post-linker) that appended data; a prior interrupted linker run that left partial trailing data; an external `-extld` that produced a non-standard tail layout.

Common situations: A build pipeline that runs `codesign` then re-invokes the Go linker; mixing `go build` with a post-processing step that pads the binary; concurrent/duplicate link invocations writing the same output file.

Related errors


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