dagger/dagger · error

failed to write updated parent go.mod: %w

Error message

failed to write updated parent go.mod: %w

What it means

Once the parent go.mod formats successfully, it is written to the in-memory overlay at path "go.mod" (parent module root == OutputDir). A WriteFile failure is wrapped here. Generation aborts after the client code was produced but before the parent module update lands.

Source

Thrown at cmd/codegen/generator/go/generate_client.go:174

		if err != nil {
			return nil, fmt.Errorf("failed to find parent go.mod: %w", err)
		}

		// Check if parent go.mod is at OutputDir or above it
		// If at OutputDir, we can write directly to overlay
		// If above OutputDir, we can't write to overlay (would be outside OutputDir), so skip this
		if parentGoModDir == g.Config.OutputDir {
			// Add require and replace to parent's go.mod
			goModFile.AddRequire(clientModuleName, "v0.0.0")
			goModFile.AddReplace(clientModuleName, "", "./"+clientRelPath, "")

			updatedParentGoMod, err := goModFile.Format()
			if err != nil {
				return nil, fmt.Errorf("failed to format parent go.mod: %w", err)
			}

			if err := mfs.WriteFile("go.mod", updatedParentGoMod, 0600); err != nil {
				return nil, fmt.Errorf("failed to write updated parent go.mod: %w", err)
			}
		}
		// If parent go.mod is outside OutputDir, we can't update it via overlay
		// The user will need to manually add require/replace directives
	}

	// We intentionally do not run `go mod tidy` here. The client go.mod pins
	// `dagger.io/dagger` at the engine version, which in a dev environment is
	// not yet published, so tidy would fail resolving it against the module
	// proxy before a replace directive is in place. Tidy is left to the caller
	// (who supplies the replace, or resolves against a real proxy once the
	// version is released / served by the dev harness).
	//
	// Note: We also don't run go mod tidy on the parent here because it would
	// remove the require directive if the parent doesn't actually import the
	// client yet. The user should run go mod tidy on the parent when ready.

	return g.generatedClientState(layerfs.New(layers...), postCmds...)

View on GitHub (pinned to 82ba2681db)

Solutions

  1. Inspect the inner wrapped error for the memfs root cause
  2. Re-run `dagger generate` from a clean state (no stale overlay artifacts)
  3. If it persists, manually add the require/replace lines to your go.mod: require <client module> v0.0.0 and replace <client module> => ./<client rel path>
  4. File an issue if reproducible, since OutputDir==parent go.mod is the supported fast path

Example fix

// manual fallback in parent go.mod
require example.com/myproject/client v0.0.0
replace example.com/myproject/client => ./dagger
Defensive patterns

Strategy: try-catch

Validate before calling

// parent go.mod must equal OutputDir for overlay write; verify before
goModData, err := os.ReadFile("go.mod")
if err != nil {
	return fmt.Errorf("parent go.mod unreadable: %w", err)
}
if _, err := modfile.Parse("go.mod", goModData, nil); err != nil {
	return fmt.Errorf("parent go.mod invalid: %w", err)
}

Try / catch

state, err := gen.GenerateClient(ctx, schema, schemaVersion)
if err != nil && strings.Contains(err.Error(), "failed to write updated parent go.mod") {
	// fallback: add directives manually
	// require <client module> v0.0.0
	// replace <client module> => ./<client dir>
	return err
}

Prevention

When it happens

Trigger: isInstall==true, parent go.mod at OutputDir, and mfs.WriteFile("go.mod", updatedParentGoMod, 0600) returns an error. Raised at generate_client.go:174.

Common situations: Overlay path collision (something else already wrote go.mod into the overlay at a conflicting state), or an internal memfs inconsistency after earlier generation steps.

Related errors


AI-assisted analysis of dagger/dagger@82ba2681db (2026-09-05). Data as JSON: /api/errors/4b1259e77af63157. Report an issue: GitHub.