wavetermdev/waveterm · error
required secret %q is not bound
Error message
required secret %q is not bound
What it means
BuildAppSecretEnv builds the environment variable map for an app by iterating manifest.Secrets. If a secret is declared non-optional (secretMeta.Optional == false) and the bindings map has no entry for it, the function fails fast with 'required secret %q is not bound'. The library refuses to launch apps whose required configuration is incomplete.
Source
Thrown at pkg/waveappstore/waveappstore.go:819
return nil
}
func BuildAppSecretEnv(appId string, manifest *wshrpc.AppManifest, bindings map[string]string) (map[string]string, error) {
if manifest == nil {
return make(map[string]string), nil
}
if bindings == nil {
bindings = make(map[string]string)
}
secretEnv := make(map[string]string)
for secretName, secretMeta := range manifest.Secrets {
boundSecretName, hasBinding := bindings[secretName]
if !secretMeta.Optional && !hasBinding {
return nil, fmt.Errorf("required secret %q is not bound", secretName)
}
if !hasBinding {
continue
}
secretValue, exists, err := secretstore.GetSecret(boundSecretName)
if err != nil {
return nil, fmt.Errorf("failed to get secret %q: %w", boundSecretName, err)
}
if !exists {
if !secretMeta.Optional {
return nil, fmt.Errorf("required secret %q is bound to %q which does not exist in secret store", secretName, boundSecretName)
}
continue
}
View on GitHub (pinned to a4447c1563)
Solutions
- Add a binding for the named secret via WriteAppSecretBindings (e.g. {"SECRET_NAME": "store-key"})
- Check the manifest's Secrets section for the exact secret name and use it verbatim (case-sensitive)
- If the secret is genuinely unnecessary, update/patch the manifest to mark it optional
- Re-read bindings with ReadAppSecretBindings to confirm what is currently bound
Example fix
// before bindings, _ := waveappstore.ReadAppSecretBindings(appId) // missing "API_KEY" env, err := waveappstore.BuildAppSecretEnv(appId, manifest, bindings) // after bindings["API_KEY"] = "myapp/api-key" // bind required secret to a store key err := waveappstore.WriteAppSecretBindings(appId, bindings) env, err := waveappstore.BuildAppSecretEnv(appId, manifest, bindings)
Defensive patterns
Strategy: validation
Validate before calling
bindings, err := waveappstore.ReadAppSecretBindings(appId)
if err != nil { return err }
for name, meta := range manifest.Secrets {
if !meta.Optional {
if _, ok := bindings[name]; !ok {
return fmt.Errorf("precheck: required secret %s unbound", name)
}
}
} Type guard
func allRequiredSecretsBound(manifest *wshrpc.AppManifest, bindings map[string]string) bool {
for name, meta := range manifest.Secrets {
if !meta.Optional {
if _, ok := bindings[name]; !ok { return false }
}
}
return true
} Try / catch
env, err := waveappstore.BuildAppSecretEnv(appId, manifest, bindings)
if err != nil && strings.Contains(err.Error(), "is not bound") {
return fmt.Errorf("app %s misconfigured: %w (run the binding command)", appId, err)
} Prevention
- After app upgrades, diff the new manifest's Secrets against current bindings
- Bind secrets immediately after install, before first run
- Keep a record of each app's required secret names
- Use exact, case-sensitive secret names from the manifest
When it happens
Trigger: Calling BuildAppSecretEnv (via runBuilderApp or GetStatus) with a manifest that declares a required secret while the bindings map returned by ReadAppSecretBindings lacks a key for that secret name.
Common situations: App was installed/upgraded to a version whose manifest added a new required secret; user never ran the binding command for that secret; secret name typo in the bindings file; bindings file was reset/emptied.
Related errors
- required secret %q is bound to %q which does not exist in se
- wcloud endpoint not set
- wcloud ping endpoint not set
- API type mismatch: chat has %s, chatOpts has %s
- model mismatch: chat has %s, chatOpts has %s
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/9a715f300a9cbbd2.
Report an issue: GitHub.