pulumi/pulumi · error

failed to watch file: %w

Error message

failed to watch file: %w

What it means

This error wraps a failure from watchFile, which tails the engine's eventlog file (logdir/eventlog.txt) so that registered event receivers can consume deployment events in watch mode. It is thrown when the underlying file watcher cannot be created — typically because the log file does not exist, cannot be opened, or the polling/fsnotify watcher fails to initialize. It is a setup failure, not a deployment failure; no events have been processed yet.

Source

Thrown at sdk/go/auto/stack.go:1968

	logDir := filepath.Dir(fw.tail.Filename)
	fw.tail.Cleanup()
	os.RemoveAll(logDir)

	// set to nil so we can safely close again in defer
	fw.tail = nil
}

func tailLogs(command string, receivers []chan<- events.EngineEvent, version semver.Version) (Watcher, error) {
	if version.LTE(semver.Version{Major: 3, Minor: 205}) {
		logDir, err := os.MkdirTemp("", fmt.Sprintf("automation-logs-%s-", command))
		if err != nil {
			return nil, fmt.Errorf("failed to create logdir: %w", err)
		}
		logFile := filepath.Join(logDir, "eventlog.txt")

		t, err := watchFile(logFile, receivers)
		if err != nil {
			return nil, fmt.Errorf("failed to watch file: %w", err)
		}

		return t, nil
	} else {
		host := newEventsServer(receivers)
		cancel := make(chan bool)
		handle, err := rpcutil.ServeWithOptions(rpcutil.ServeOptions{
			Init: func(srv *grpc.Server) error {
				pulumirpc.RegisterEventsServer(srv, host)
				return nil
			},
			Cancel:  cancel,
			Options: rpcutil.TracingServerInterceptorOptions(nil),
		})
		if err != nil {
			return nil, err
		}
		return &eventsWatcher{

View on GitHub (pinned to 793f7b2e16)

Solutions

  1. Check that the log directory (PULUMI_DEBUG_GRPC... / logdir path) is writable by the process user and that the eventlog.txt file exists before watching
  2. Retry the watch call — the log file may not have been flushed/created yet at watch time
  3. Ensure only one watcher is started per stack run to avoid races on the logdir
  4. Inspect the wrapped error (%w) for the root cause: open failure, permission denied, or watcher init error

Example fix

// before
t, err := stack.Watch(ctx)
if err != nil { return err }

// after
t, err := stack.Watch(ctx)
if err != nil {
    if os.IsPermission(errors.Unwrap(err)) {
        // fix logdir permissions or choose another log dir
    }
    return fmt.Errorf("watch setup failed: %w", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := os.Stat(filepath.Join(logDir, "eventlog.txt")); err != nil {
    return fmt.Errorf("eventlog not available: %w", err)
}

Try / catch

t, err := stack.Watch(ctx)
if err != nil {
    var perr *fs.PathError
    if errors.As(err, &perr) {
        // handle missing/unreadable eventlog before retrying
    }
    return err
}

Prevention

When it happens

Trigger: Calling Watch/WatchAsync on an automation API Stack with Debugging or EventLog watchers enabled, when watchFile(logFile, receivers) fails — e.g. the eventlog file was not created because logDir creation succeeded but the watcher cannot open the file (permissions, file deleted concurrently, invalid logdir path).

Common situations: Running Pulumi operations in restricted sandboxes/containers where /tmp or the logdir is read-only; antivirus or log rotation deleting the eventlog file mid-setup; disk full preventing the log file from being created; concurrent Watch calls racing on the same stack's logdir.

Related errors


AI-assisted analysis of pulumi/pulumi@793f7b2e16 (2026-08-31). Data as JSON: /api/errors/cfa1e04127e30882. Report an issue: GitHub.