golang/go · error

reading go.work: %w

Error message

reading go.work: %w

What it means

ReadWorkFile could not read the bytes of go.work from disk (fsys.ReadFile failed). The raw I/O error is wrapped with %w under the 'reading go.work:' prefix. This is a filesystem-level failure before any parsing is attempted.

Source

Thrown at src/cmd/go/internal/modload/init.go:839

		seen[modRoot] = true
		modRoots = append(modRoots, modRoot)
	}

	for _, g := range wf.Godebug {
		if err := CheckGodebug("godebug", g.Key, g.Value); err != nil {
			return nil, nil, fmt.Errorf("error loading go.work:\n%s:%d: %w", base.ShortPath(path), g.Syntax.Start.Line, err)
		}
	}

	return wf, modRoots, nil
}

// ReadWorkFile reads and parses the go.work file at the given path.
func ReadWorkFile(path string) (*modfile.WorkFile, error) {
	path = base.ShortPath(path) // use short path in any errors
	workData, err := fsys.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("reading go.work: %w", err)
	}

	f, err := modfile.ParseWork(path, workData, nil)
	if err != nil {
		return nil, fmt.Errorf("errors parsing go.work:\n%w", err)
	}
	if f.Go != nil && gover.Compare(f.Go.Version, gover.Local()) > 0 && cfg.CmdName != "work edit" {
		base.Fatal(&gover.TooNewError{What: base.ShortPath(path), GoVersion: f.Go.Version})
	}
	return f, nil
}

// WriteWorkFile cleans and writes out the go.work file to the given path.
func WriteWorkFile(path string, wf *modfile.WorkFile) error {
	wf.SortBlocks()
	wf.Cleanup()
	out := modfile.Format(wf.Syntax)

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Verify the file is readable: 'ls -l go.work' and 'cat go.work'; fix permissions (chmod 644).
  2. If a symlink, ensure its target exists and is readable.
  3. Confirm GO_GOWORK / GOWORK env does not point at a stale or wrong path.
  4. If the file should not be used, unset GO_GOWORK or move/delete it so Go stops trying to read it.

Example fix

// before
$ go build ./...
// reading go.work: open /repo/go.work: permission denied
$ ls -l go.work
---------- 1 root root 0 ... go.work

// after
$ chmod 644 go.work
$ go build ./...
Defensive patterns

Strategy: validation

Validate before calling

// Ensure go.work is readable before building.
if fi, err := os.Stat("go.work"); err == nil {
    if fi.Mode().Perm()&0400 == 0 {
        return fmt.Errorf("go.work not readable: mode %v", fi.Mode().Perm())
    }
    if _, err := os.ReadFile("go.work"); err != nil {
        return fmt.Errorf("go.work unreadable: %w", err)
    }
} else if !os.IsNotExist(err) {
    return err
}

Try / catch

out, err := exec.Command("go", "build", "./...").CombinedOutput()
if err != nil && bytes.Contains(out, []byte("reading go.work")) {
    // filesystem issue; surface and stop (do not retry without fixing perms/mounts)
    return fmt.Errorf("go.work unreadable, check perms/mount: %s", out)
}
return err

Prevention

When it happens

Trigger: go.work path exists but is unreadable: permission denied, I/O error, broken symlink, or the path is a directory. Triggered when Go detects GO_GOWORK / walks up to find a go.work and then tries to read it.

Common situations: Tightened file modes (chmod 000 go.work), a CI step that touch'd go.work without write perms, a symlink to a missing target, an encrypted/sealed filesystem not yet unlocked.

Related errors


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