golang/go · error

fail to seek

Error message

fail to seek

What it means

Returned by peBiobuf.ReadAt when the underlying bio.Reader.MustSeek returns a negative value, indicating the seek to the requested offset failed. peBiobuf adapts a buffered I/O reader to the io.ReaderAt interface so PE section readers (which use ReadAt) can random-access the linker's input. A failed seek means the requested offset is unreachable on the stream backing the PE file.

Source

Thrown at src/cmd/link/internal/loadpe/ldpe.go:159

	// that loads from the corresponding import symbol and then does
	// a jump to the loaded value.
	CreateImportStubPltToken = -2

	// When stored into the GOT value for an import symbol __imp_X this
	// token tells windynrelocsym to redirect references to the
	// underlying DYNIMPORT symbol X.
	RedirectToDynImportGotToken = -2
)

// TODO(brainman): maybe just add ReadAt method to bio.Reader instead of creating peBiobuf

// peBiobuf makes bio.Reader look like io.ReaderAt.
type peBiobuf bio.Reader

func (f *peBiobuf) ReadAt(p []byte, off int64) (int, error) {
	ret := ((*bio.Reader)(f)).MustSeek(off, 0)
	if ret < 0 {
		return 0, errors.New("fail to seek")
	}
	n, err := f.Read(p)
	if err != nil {
		return 0, err
	}
	return n, nil
}

// makeUpdater creates a loader.SymbolBuilder if one hasn't been created previously.
// We use this to lazily make SymbolBuilders as we don't always need a builder, and creating them for all symbols might be an error.
func makeUpdater(l *loader.Loader, bld *loader.SymbolBuilder, s loader.Sym) *loader.SymbolBuilder {
	if bld != nil {
		return bld
	}
	bld = l.MakeSymbolUpdater(s)
	return bld
}

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Rebuild or re-fetch the offending PE input (object/import library/DLL) — truncation is the usual cause.
  2. Verify the file integrity with `go tool nm` or a PE inspector (dumpbin/objdump) before linking.
  3. If the file is valid, ensure the linker is reading the same file (check -I/-L paths and build cache for stale copies).
  4. Check for disk-full or interrupted-write artifacts in the build cache; `go clean -cache` and rebuild.

Example fix

// before: linking a truncated .dll
go build -o app.exe
// ldpe: fail to seek

// after: re-fetch and rebuild
go clean -cache
# ensure the import library is complete, then:
go build -o app.exe
Defensive patterns

Strategy: validation

Validate before calling

// Verify the PE input is complete and its sections are within EOF before linking.
func peSectionsWithinEOF(path string) error {
    f, err := os.Open(path)
    if err != nil { return err }
    defer f.Close()
    fi, _ := f.Stat()
    pf, err := pe.NewFile(f)
    if err != nil { return err }
    for _, s := range pf.Sections {
        if int64(s.Offset)+int64(s.Size) > fi.Size() {
            return fmt.Errorf("section %s extends past EOF", s.Name)
        }
    }
    return nil
}

Type guard

func isSeekFail(err error) bool {
    return err != nil && err.Error() == "fail to seek"
}

Try / catch

if err := loadpe.Load(...); err != nil && err.Error() == "fail to seek" {
    return fmt.Errorf("PE input %s appears truncated: %w", pn, err)
}

Prevention

When it happens

Trigger: The PE loader (loadpe) calls ReadAt on a section offset that lies outside the buffered reader's valid range — typically because the file is truncated, the PE section header claims a larger offset/size than the file provides, or the reader's position was corrupted. MustSeek(off,0) < 0 triggers the error.

Common situations: Linking against a truncated or partially-written Windows .obj/.dll, a corrupt PE produced by a crashed build, or a PE with malformed section headers pointing past EOF. Often seen when cgo links a Windows resource or import library that was incompletely downloaded.

Related errors


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