charmbracelet/crush · error

invalid lsp env: %w

Error message

invalid lsp env: %w

What it means

createPowernapClient resolves the environment map passed to the spawned LSP server via c.config.ResolvedEnv(c.resolver). If an environment entry's key or value contains an unresolvable expansion, construction fails with "invalid lsp env". This is the third of three config-resolution steps before the powernap client is built.

Source

Thrown at internal/lsp/client.go:203

}

// createPowernapClient creates a new powernap client with the current configuration.
func (c *Client) createPowernapClient() error {
	rootURI := string(protocol.URIFromPath(c.cwd))

	command, err := c.resolver.ResolveValue(c.config.Command)
	if err != nil {
		return fmt.Errorf("invalid lsp command: %w", err)
	}

	args, err := c.config.ResolvedArgs(c.resolver)
	if err != nil {
		return fmt.Errorf("invalid lsp args: %w", err)
	}

	envs, err := c.config.ResolvedEnv(c.resolver)
	if err != nil {
		return fmt.Errorf("invalid lsp env: %w", err)
	}

	clientConfig := powernap.ClientConfig{
		Command:     home.Long(command),
		Args:        args,
		RootURI:     rootURI,
		Environment: envs,
		Settings:    c.config.Options,
		InitOptions: c.config.InitOptions,
		WorkspaceFolders: []protocol.WorkspaceFolder{
			{
				URI:  rootURI,
				Name: filepath.Base(c.cwd),
			},
		},
	}

	powernapClient, err := powernap.NewClient(clientConfig)

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Export or define the variables referenced in the lsp env map before launching.
  2. Remove or hardcode env entries that don't need templating.
  3. Correct placeholder syntax in env keys/values to match resolver expectations.
  4. Verify by echoing the variables in the same environment crush runs in.

Example fix

// before
env = { GOFLAGS = "${CUSTOM_GOFLAGS}" } // unset in CI

// after
env = { GOFLAGS = "-tags=integration" }
Defensive patterns

Strategy: validation

Validate before calling

for k, v := range lspCfg.Env {
    if strings.Contains(v, "${") {
        expanded := os.ExpandEnv(v)
        if strings.Contains(expanded, "${") {
            return fmt.Errorf("env %s=%q has unresolvable expansion", k, v)
        }
    }
}

Type guard

func validLSPEnv(env map[string]string) bool {
    for _, v := range env {
        if strings.Count(v, "${") != strings.Count(os.ExpandEnv(v), "${") {
            return false
        }
    }
    return true
}

Try / catch

client, err := lsp.New(cfg)
if err != nil && strings.Contains(err.Error(), "invalid lsp env") {
    slog.Error("LSP env resolution failed; verify referenced variables exist", "env", cfg.Env, "error", err)
    return err
}

Prevention

When it happens

Trigger: Calling New or Restart where config.ResolvedEnv(c.resolver) errors — e.g. env entry "GOPATH=${MY_GOPATH}" with MY_GOPATH unset, or an invalid expansion expression inside an env value.

Common situations: LSP config sets custom env for the server using variables absent in the host environment (CI runners, cron, services with minimal env); malformed placeholder syntax in an env value.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/6c2ba3b46c9481ac. Report an issue: GitHub.