apache/answer · error

failed to install plugin dependencies: %w

Error message

failed to install plugin dependencies: %w

What it means

For each vendored plugin that has a package.json (i.e. a UI plugin), copyUIFiles runs `pnpm install` inside the plugin's source directory to install its frontend dependencies. This error wraps the exec.ExitError from a failing pnpm install — the plugin's JS dependencies could not be installed.

Source

Thrown at internal/cli/build.go:368

	if err != nil {
		return fmt.Errorf("failed to read plugins dir: %w", err)
	}
	for _, entry := range pluginsDirEntries {
		if !entry.IsDir() {
			continue
		}
		sourcePluginDir := filepath.Join(pluginsDir, entry.Name())
		// check if plugin is a ui plugin
		packageJsonPath := filepath.Join(sourcePluginDir, "package.json")
		fmt.Printf("check if %s is a ui plugin\n", packageJsonPath)
		if !dir.CheckFileExist(packageJsonPath) {
			continue
		}

		pnpmInstallCmd := b.newExecCmd("pnpm", "install")
		pnpmInstallCmd.Dir = sourcePluginDir
		if err = pnpmInstallCmd.Run(); err != nil {
			return fmt.Errorf("failed to install plugin dependencies: %w", err)
		}

		localPluginDir := filepath.Join(localUIPluginDir, entry.Name())
		fmt.Printf("try to copy dir from %s to %s\n", sourcePluginDir, localPluginDir)
		if err = copyDirEntries(os.DirFS(sourcePluginDir), ".", localPluginDir, "node_modules"); err != nil {
			return fmt.Errorf("failed to copy ui files: %w", err)
		}
	}
	formatUIPluginsDirName(localUIPluginDir)
	return nil
}

// buildUI run pnpm install and pnpm build commands to build ui
func buildUI(b *buildingMaterial) (err error) {
	localUIBuildDir := filepath.Join(b.tmpDir, "vendor/github.com/apache/answer/ui")

	pnpmInstallCmd := b.newExecCmd("pnpm", "pre-install")
	pnpmInstallCmd.Dir = localUIBuildDir

View on GitHub (pinned to 3b9f137061)

Solutions

  1. Ensure pnpm is installed and on PATH (`pnpm -v`); install the version the answer build expects (e.g. `npm i -g pnpm` or corepack).
  2. Reproduce manually: `cd <plugin-dir> && pnpm install` and read the pnpm output to see the real failure (registry 404, peer conflict, Node version).
  3. Fix the plugin's package.json/pnpm-lock.yaml: update deps or run `pnpm install --no-frozen-lockfile`; for private/old packages check registry access.
  4. Check network/proxy config for pnpm (npm registry mirror, HTTPS_PROXY) and Node version compatibility, then rebuild.

Example fix

// before: pnpm failure surfaced with no context
pnpmInstallCmd := b.newExecCmd("pnpm", "install")
pnpmInstallCmd.Dir = sourcePluginDir
if err = pnpmInstallCmd.Run(); err != nil {
	return fmt.Errorf("failed to install plugin dependencies: %w", err)
}
// after: verify pnpm availability and capture output
if _, err := exec.LookPath("pnpm"); err != nil {
	return fmt.Errorf("pnpm is required to build UI plugins: %w", err)
}
pnpmInstallCmd := b.newExecCmd("pnpm", "install")
pnpmInstallCmd.Dir = sourcePluginDir
pnpmInstallCmd.Stdout = os.Stdout
pnpmInstallCmd.Stderr = os.Stderr
if err = pnpmInstallCmd.Run(); err != nil {
	return fmt.Errorf("failed to install plugin dependencies in %s: %w", sourcePluginDir, err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := exec.LookPath("pnpm"); err != nil {
	return fmt.Errorf("pnpm not found in PATH; install it (npm i -g pnpm or corepack enable)")
}
pkgJson := filepath.Join(sourcePluginDir, "package.json")
if _, err := os.Stat(pkgJson); err != nil {
	return fmt.Errorf("plugin %s has no package.json", sourcePluginDir)
}
// optional connectivity check
if err := probeRegistry("https://registry.npmjs.org"); err != nil {
	return fmt.Errorf("npm registry unreachable; check proxy/network: %w", err)
}

Type guard

func pnpmAvailable() bool {
	p, err := exec.LookPath("pnpm")
	return err == nil && p != ""
}
func isUIPlugin(pluginDir string) bool {
	fi, err := os.Stat(filepath.Join(pluginDir, "package.json"))
	return err == nil && !fi.IsDir()
}

Try / catch

var exitErr *exec.ExitError
if err := pnpmInstallCmd.Run(); err != nil {
	if errors.As(err, &exitErr) {
		return fmt.Errorf("pnpm install failed in %s (exit %d); run 'cd %s && pnpm install' for details: %w",
			sourcePluginDir, exitErr.ExitCode(), sourcePluginDir, err)
	}
	return fmt.Errorf("failed to start pnpm (is it installed?): %w", err)
}

Prevention

When it happens

Trigger: b.newExecCmd("pnpm", "install").Run() with Dir=sourcePluginDir returns an error: pnpm binary not on PATH, the plugin's package.json/pnpm-lock.yaml is broken or references unpublished versions/registry packages, network failure reaching the npm registry, or pnpm exits non-zero (peer conflicts, unsupported Node version).

Common situations: Custom third-party plugin with an outdated lockfile or dependencies that no longer resolve; corporate proxy/firewall blocking registry.npmjs.org; pnpm not installed (answer build requires it) or wrong Node/pnpm version; plugin's package.json pinned to a removed package version.

Related errors


AI-assisted analysis of apache/answer@3b9f137061 (2026-09-05). Data as JSON: /api/errors/f17ee678742181c6. Report an issue: GitHub.