gohugoio/hugo · error

got unexpected EOF when executing

Error message

got unexpected EOF when executing %q. The user running hugo must have read and execute permissions on this program. With execute permissions only, this error is thrown.

What it means

Returned by the Dart Sass toCSS path when c.transpiler.Execute returns an error whose message is exactly 'unexpected EOF'. Hugo interprets this specific embedded-protocol error as a filesystem permission problem: the dart-sass-embedded binary was invoked but the Hugo process lacks read permission on it (execute-only). The message guides the user to fix permissions on the binary.

Solutions

  1. Grant read+execute on the Dart Sass binary to the Hugo user, e.g. `chmod 0755 $(which sass)` or `chmod o+rx /path/to/dart-sass-embedded`.
  2. Ensure the user running hugo also owns or is in the owning group of the binary and its parent directories.
  3. Reinstall Dart Sass via a method that sets standard 0755 permissions.

Example fix

// before
$ ls -l $(which sass)
-rwx--x--x ... sass

// after
$ sudo chmod 0755 $(which sass)
$ ls -l $(which sass)
-rwxr-xr-x ... sass
Defensive patterns

Strategy: validation

Validate before calling

// Verify read+execute permission on the Dart Sass binary for the Hugo user.
func binaryReadable(bin string) error {
    fi, err := os.Stat(bin)
    if err != nil { return err }
    mode := fi.Mode().Perm()
    if mode&0004 == 0 { // others-read
        return fmt.Errorf("%s not world-readable (mode %o); chmod 0755", bin, mode)
    }
    return nil
}

Prevention

When it happens

Trigger: css.Sass/ToCSS with transpiler='dartsass' runs, the embedded binary starts, but reading its executable image (or a temp/protocol file) fails because the running user has execute but not read permission on hugo.DartSassBinaryName, producing 'unexpected EOF' from the transpiler.

Common situations: Binary installed with mode 0711 or 0111 (execute-only, no read), common in hardened/containerized environments or when an installer drops read bits; running Hugo as a different user than the binary owner without group read.

Related errors


AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09). Data as JSON: /api/errors/724d2c54318b23df. Report an issue: GitHub.

Appendix: source

Thrown at resources/resource_transformers/tocss/dartsass/client.go:124

}

func (c *Client) Close() error {
	if c.transpiler == nil {
		return nil
	}
	return c.transpiler.Close()
}

func (c *Client) toCSS(args godartsass.Args, src io.Reader) (godartsass.Result, error) {
	in := helpers.ReaderToString(src)

	args.Source = in

	res, err := c.transpiler.Execute(args)
	if err != nil {
		if err.Error() == "unexpected EOF" {
			//lint:ignore ST1005 end user message.
			return res, fmt.Errorf("got unexpected EOF when executing %q. The user running hugo must have read and execute permissions on this program. With execute permissions only, this error is thrown.", hugo.DartSassBinaryName)
		}
		return res, herrors.NewFileErrorFromFileInErr(err, hugofs.Os, herrors.OffsetMatcher)
	}

	return res, err
}

type Options struct {
	// Hugo, will by default, just replace the extension of the source
	// to .css, e.g. "scss/main.scss" becomes "scss/main.css". You can
	// control this by setting this, e.g. "styles/main.css" will create
	// a Resource with that as a base for RelPermalink etc.
	TargetPath string

	// Hugo automatically adds the entry directories (where the main.scss lives)
	// for project and themes to the list of include paths sent to LibSASS.
	// Any paths set in this setting will be appended. Note that these will be
	// treated as relative to the working dir, i.e. no include paths outside the

View on GitHub (pinned to 52c9bd7908)