larksuite/cli · error
appSecret is empty string
Error message
appSecret is empty string
What it means
When ResolveSecretInput receives a plain-string SecretInput, resolvePlainOrTemplate checks the string before env-template expansion. This error means the plain string form was selected (Ref == nil) but the string itself is empty — a literal empty appSecret value like "" in openclaw.json. It is distinct from error 161 (no appSecret at all): here the key exists but holds an empty string.
Source
Thrown at internal/binding/secret_resolve.go:40
}
if input.IsZero() {
return "", fmt.Errorf("appSecret is missing or empty")
}
// Plain string form (includes env templates)
if input.IsPlain() {
return resolvePlainOrTemplate(input.Plain, getenv)
}
// 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.View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Replace the empty string with the actual app secret value in openclaw.json.
- Better: set "appSecret": "${FEISHU_APP_SECRET}" and export the variable in the environment so the secret is never stored in the file.
- In code, pre-validate: if input.IsPlain() && input.Plain == "" { reject before resolve }.
- If the channel is not yet configured, either remove appSecret (surfacing error 161) or set "enabled": false.
Example fix
// before
"appSecret": ""
// after
"appSecret": "${FEISHU_APP_SECRET}" Defensive patterns
Strategy: validation
Validate before calling
if input.IsPlain() && input.Plain == "" {
return fmt.Errorf("openclaw config: appSecret must be a non-empty string or a secret reference")
} Type guard
func hasNonEmptyPlainSecret(in binding.SecretInput) bool {
return in.IsPlain() && in.Plain != ""
} Try / catch
secret, err := binding.ResolveSecretInput(input, cfg, os.Getenv)
if err != nil {
if strings.Contains(err.Error(), "appSecret is empty string") {
return fmt.Errorf("appSecret in openclaw.json is \"\"; set the real secret or an env template: %w", err)
}
return err
} Prevention
- When substituting template placeholders, assert the substituted value is non-empty before writing the file.
- Prefer "${VAR}" templates over injecting literal empty strings from unset CI variables.
- Add a config pre-flight that flags any "" string field for appSecret.
- Remove the appSecret key entirely rather than blanking it when rotating.
When it happens
Trigger: openclaw.json contains "appSecret": "" (or accounts.<label>.appSecret set to ""), so SecretInput{Plain: ""} reaches resolvePlainOrTemplate and fails the value == "" check. Can also happen when a template engine or script wrote an empty substituted value.
Common situations: A placeholder was replaced with nothing during provisioning; a user cleared the secret in the editor but left the key; a CI template rendered ${SECRET} from an unset variable, producing "appSecret": "".
Related errors
- appSecret is missing or empty
- env variable %q referenced in openclaw.json is not set or em
- unsupported secret source %q
- file provider path is empty
- singleValue file provider expects ref id %q, got %q
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/028286281b966d7f.
Report an issue: GitHub.