gohugoio/hugo · info

errNoSuchWatch

errNoSuchWatch

Error message

watch does not exist

What it means

errNoSuchWatch (watcher/filenotify/poller.go:19) is returned by the polling file watcher's Remove(name) when the given path isn't in its watches map. It indicates an attempt to unwatch a file/directory that was never added or was already removed, keeping Remove's contract symmetric with fsnotify's behavior.

Source

Thrown at watcher/filenotify/poller.go:19

package filenotify

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"sync"
	"time"

	"github.com/fsnotify/fsnotify"
	"github.com/gohugoio/hugo/common/herrors"
)

var (
	// errPollerClosed is returned when the poller is closed
	errPollerClosed = errors.New("poller is closed")
	// errNoSuchWatch is returned when trying to remove a watch that doesn't exist
	errNoSuchWatch = errors.New("watch does not exist")
)

// filePoller is used to poll files for changes, especially in cases where fsnotify
// can't be run (e.g. when inotify handles are exhausted)
// filePoller satisfies the FileWatcher interface
type filePoller struct {
	// the duration between polls.
	interval time.Duration
	// watches is the list of files currently being polled, close the associated channel to stop the watch
	watches map[string]struct{}
	// Will be closed when done.
	done chan struct{}
	// events is the channel to listen to for watch events
	events chan fsnotify.Event
	// errors is the channel to listen to for watch errors
	errors chan error
	// mu locks the poller for modification
	mu sync.Mutex

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Generally harmless — Hugo tolerates it during watch-set updates; ignore one-off occurrences.
  2. Restart `hugo server` if watching becomes inconsistent after heavy file churn.
  3. Avoid polling mode where possible (fix inotify limits instead of --poll) to reduce watch-set races.
Defensive patterns

Strategy: type-guard

Validate before calling

// track what you've added
if !watched[path] { return } // nothing to remove

Type guard

func isNoSuchWatch(err error) bool { return err != nil && err.Error() == "watch does not exist" }

Try / catch

if err := w.Remove(path); err != nil {
    if isNoSuchWatch(err) { /* already removed — idempotent, ignore */ } else { return err }
}

Prevention

When it happens

Trigger: filePoller.Remove(name) called for a path absent from w.watches — e.g. Hugo's server removing a watch for a deleted/renamed directory that was already unwatched, or double-removal during watcher reconfiguration.

Common situations: Rapid delete/rename churn of content or asset directories while `hugo server` runs in polling mode (--poll, network mounts, exhausted inotify); module/mount config changes that rebuild the watch set and remove paths twice.

Related errors


AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31). Data as JSON: /data/errors/d9b5033c73ed34d3.json. Report an issue: GitHub ↗.