AdguardTeam/AdGuardHome · critical

getting embedded client subdir: %w

Error message

getting embedded client subdir: %w

What it means

AdGuard Home failed to obtain the sub-filesystem 'build/static' from the embedded frontend assets via fs.Sub. This happens during newWeb when the embedded build directory structure doesn't match expectations, typically because the binary was built without the frontend assets embedded or the embed path changed between versions.

Source

Thrown at internal/home/home.go:690

	// isFirstRun defines if current run is the first run.
	isFirstRun bool
}

// newWeb initializes the web module.  conf must not be nil.
func newWeb(ctx context.Context, conf *webConfig) (web *webAPI, err error) {
	logger := conf.baseLogger.With(slogutil.KeyPrefix, "webapi")

	webPort := suggestedWebPort(ctx, logger)

	var clientFS fs.FS
	if conf.opts.localFrontend {
		logger.WarnContext(ctx, "using local frontend files")

		clientFS = os.DirFS("build/static")
	} else {
		clientFS, err = fs.Sub(conf.clientBuildFS, "build/static")
		if err != nil {
			return nil, fmt.Errorf("getting embedded client subdir: %w", err)
		}
	}

	disableUpdate := !isUpdateEnabled(ctx, conf.baseLogger, &conf.opts, conf.isCustomUpdURL)

	webConf := &webAPIConfig{
		CommandConstructor: executil.SystemCommandConstructor{},
		updater:            conf.updater,
		logger:             logger,
		baseLogger:         conf.baseLogger,
		confModifier:       conf.configModifier,
		httpReg:            conf.httpReg,
		tlsManager:         conf.tlsManager,
		auth:               conf.auth,
		mux:                conf.mux,
		hostsContainer:     conf.hostsContainer,

		clientFS: clientFS,

View on GitHub (pinned to b41aefbe51)

Solutions

  1. Rebuild the binary with the frontend: run ./scripts/make or at least the frontend build step so build/static is generated before go build
  2. If running from a checkout, place frontend files under build/static and run with local-frontend mode instead of relying on the embed
  3. Verify the embed.FS variable in internal/home still matches the 'build/static' path for your version

Example fix

// before: built without frontend
go build ./

// after: build frontend then embed
cd frontend && yarn && yarn build
cd .. && go build ./
Defensive patterns

Strategy: validation

Validate before calling

// Before running, verify embedded assets exist in your build:
if _, err := fs.Sub(clientBuildFS, "build/static"); err != nil {
    log.Fatal("frontend assets missing; rebuild with ./scripts/make")
}

Try / catch

if err := run(ctx); err != nil {
    if strings.Contains(err.Error(), "getting embedded client subdir") {
        log.Fatalf("frontend not embedded: %v — rebuild with the frontend step", err)
    }
    log.Fatal(err)
}

Prevention

When it happens

Trigger: Calling run/newWeb (binary startup) when conf.clientBuildFS doesn't contain a 'build/static' directory — e.g. building with a build tag or environment that skips frontend embedding, or a corrupted/modified embed directive in internal/home.

Common situations: Custom builds from source that omit the frontend (make: skipping node build), stale embed cache after switching branches, or downstream packaging that strips embedded files.

Related errors


AI-assisted analysis of AdguardTeam/AdGuardHome@b41aefbe51 (2026-08-27). Data as JSON: /api/errors/3b78f22de53adbda. Report an issue: GitHub.