larksuite/cli · error

env variable %q referenced in openclaw.json is not set or em

Error message

env variable %q referenced in openclaw.json is not set or empty

What it means

resolvePlainOrTemplate expands "${VAR_NAME}" env templates in plain appSecret strings using the injected getenv (default os.Getenv). This error means the template matched EnvTemplateRe (uppercase name, 1-128 chars) but the referenced environment variable is unset or empty, so the secret cannot be resolved to a usable value. The variable name is quoted in the message.

Source

Thrown at internal/binding/secret_resolve.go:49

	}

	// SecretRef object form
	return resolveSecretRef(input.Ref, cfg, getenv)
}

// resolvePlainOrTemplate handles plain strings and "${VAR}" templates.
func resolvePlainOrTemplate(value string, getenv func(string) string) (string, error) {
	if value == "" {
		return "", fmt.Errorf("appSecret is empty string")
	}

	// Check for env template pattern: "${VAR_NAME}"
	matches := EnvTemplateRe.FindStringSubmatch(value)
	if matches != nil {
		varName := matches[1]
		envValue := getenv(varName)
		if envValue == "" {
			return "", fmt.Errorf("env variable %q referenced in openclaw.json is not set or empty", varName)
		}
		return envValue, nil
	}

	// Plain string: use as-is
	return value, nil
}

// resolveSecretRef dispatches a SecretRef to the appropriate sub-resolver.
func resolveSecretRef(ref *SecretRef, cfg *SecretsConfig, getenv func(string) string) (string, error) {
	// Lookup provider configuration
	providerConfig, err := LookupProvider(ref, cfg)
	if err != nil {
		return "", err
	}

	// Resolve the effective provider name once so downstream resolvers
	// (notably the exec JSON payload) see the config-defaulted value instead

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Export the named variable with a non-empty value in the same environment that runs the bind: export FEISHU_APP_SECRET=... then re-run.
  2. Verify the exact name/typo: echo "${FEISHU_APP_SECRET}" in the failing shell; the message shows the name being looked up.
  3. If using a .env file, source it (set -a; . ./.env; set +a) or use the launcher (direnv, systemd EnvironmentFile) that forwards it to the process.
  4. Fix empty-string exports: a variable set to "" still fails; ensure a real secret value.
  5. In code, pre-check with the same getenv: os.LookupEnv(name) and reject !ok || value == "" before binding.

Example fix

// before (shell)
lark bind  # FEISHU_APP_SECRET not exported
// after
export FEISHU_APP_SECRET="xxxx"
lark bind
Defensive patterns

Strategy: validation

Validate before calling

func checkEnvTemplates(data []byte, lookup func(string) (string, bool)) error {
	re := regexp.MustCompile(`^\$\{([A-Z][A-Z0-9_]{0,127})\}$`)
	var cfg struct {
		Channels struct {
			Feishu struct {
				AppSecret string `json:"appSecret"`
			} `json:"feishu"`
		} `json:"channels"`
	}
	if err := json.Unmarshal(data, &cfg); err != nil { return err }
	v := cfg.Channels.Feishu.AppSecret
	if strings.HasPrefix(v, "${") && strings.HasSuffix(v, "}") {
		name := re.FindStringSubmatch(v)
		if name == nil { return nil }
		if val, ok := lookup(name[1]); !ok || val == "" {
			return fmt.Errorf("env variable %s must be exported before binding", name[1])
		}
	}
	return nil
}

Type guard

func envVarSet(name string) bool {
	v, ok := os.LookupEnv(name)
	return ok && v != ""
}

Try / catch

secret, err := binding.ResolveSecretInput(input, cfg, os.Getenv)
if err != nil {
	var envErr *os.PathError // not expected; demonstrate typed inspection
	_ = envErr
	if m := regexp.MustCompile(`env variable "([^"]+)"`).FindStringSubmatch(err.Error()); m != nil {
		return fmt.Errorf("export %s before running bind (see .env / shell profile): %w", m[1], err)
	}
	return err
}

Prevention

When it happens

Trigger: openclaw.json has "appSecret": "${SOME_VAR}" and getenv("SOME_VAR") returns "" at bind time: the variable was never exported, was exported only in another shell/session, was misspelled, or is set to empty string. Note the regex anchors the whole string, so "prefix${VAR}" does not match the template branch at all.

Common situations: Secret exported in ~/.zshrc but the CLI runs under a systemd unit or CI job without it; dotenv file not sourced before running bind; variable name typo between openclaw.json and export statement; secrets manager wrote an empty value.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/29f3cf77d9977dce. Report an issue: GitHub.