wavetermdev/waveterm · error
required secret %q is bound to %q which does not exist in se
Error message
required secret %q is bound to %q which does not exist in secret store
What it means
When a required (non-optional) secret has a binding but the bound key does not exist in the secret store (GetSecret returns exists=false with no error), BuildAppSecretEnv refuses to proceed with 'required secret %q is bound to %q which does not exist in secret store'. This distinguishes a dangling binding from an unbound secret.
Source
Thrown at pkg/waveappstore/waveappstore.go:833
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
}
secretEnv[secretName] = secretValue
}
return secretEnv, nil
}
View on GitHub (pinned to a4447c1563)
Solutions
- Re-store the secret under the bound key name (e.g. secretstore.SetSecret(boundSecretName, value))
- Or update the binding via WriteAppSecretBindings to point at the correct existing key
- Verify the exact key name in the store (watch for typos, case, and namespace prefixes)
- If the secret is not actually needed, mark it optional in the manifest or remove the requirement
Example fix
// before
bindings := map[string]string{"API_KEY": "myapp/api-key"} // key missing in store
// after
secretstore.SetSecret("myapp/api-key", actualKeyValue) // or:
bindings["API_KEY"] = "myapp/api-key-v2" // point at the real stored key
waveappstore.WriteAppSecretBindings(appId, bindings) Defensive patterns
Strategy: validation
Validate before calling
for secretName, boundKey := range bindings {
if meta := manifest.Secrets[secretName]; meta != nil && !meta.Optional {
if _, exists, err := secretstore.GetSecret(boundKey); err == nil && !exists {
return fmt.Errorf("precheck: key %q missing for required secret %s", boundKey, secretName)
}
}
} Type guard
func boundKeysExist(manifest *wshrpc.AppManifest, bindings map[string]string) bool {
for name, key := range bindings {
meta, ok := manifest.Secrets[name]
if ok && !meta.Optional {
if _, exists, err := secretstore.GetSecret(key); err != nil || !exists { return false }
}
}
return true
} Try / catch
env, err := waveappstore.BuildAppSecretEnv(appId, manifest, bindings)
if err != nil && strings.Contains(err.Error(), "does not exist in secret store") {
return fmt.Errorf("dangling binding — re-store the secret or rebind: %w", err)
} Prevention
- When deleting a secret from the store, also remove its bindings
- Use a single source of truth for store key names (constants, not literals)
- After migrating machines, re-store all required secrets
- Verify bound keys exist right after writing bindings
When it happens
Trigger: Bindings map contains secretName -> boundSecretName, secretMeta.Optional is false, and secretstore.GetSecret(boundSecretName) reports the key does not exist.
Common situations: The secret was deleted from the store after being bound; the binding points to a key under a different store namespace; the secret was stored on another machine/user profile; key name typo or case mismatch between binding and stored key; app copied to a new machine whose store lacks the entry.
Related errors
- required secret %q is not bound
- 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/01ddc6951ca100c8.
Report an issue: GitHub.