wavetermdev/waveterm · error
failed to read secret bindings (ERR-SECRET): %w
Error message
failed to read secret bindings (ERR-SECRET): %w
What it means
After the manifest, runBuilderApp reads the app's secret bindings via waveappstore.ReadAppSecretBindings. This error (tagged ERR-SECRET) means the stored secret bindings file for the app could not be read or decrypted, so the app cannot be launched with its secrets.
Source
Thrown at pkg/buildercontroller/buildercontroller.go:312
bc.lock.Lock()
if bc.process == process {
bc.process = nil
exitCode := exitCodeFromWaitErr(process.WaitRtn)
bc.setStatus_nolock(BuilderStatus_Stopped, 0, exitCode, "")
}
bc.lock.Unlock()
}()
}
func (bc *BuilderController) runBuilderApp(ctx context.Context, appId string, appBinPath string, builderEnv map[string]string) (*BuilderProcess, error) {
manifest, err := waveappstore.ReadAppManifest(appId)
if err != nil {
return nil, fmt.Errorf("failed to read app manifest: %w", err)
}
secretBindings, err := waveappstore.ReadAppSecretBindings(appId)
if err != nil {
return nil, fmt.Errorf("failed to read secret bindings (ERR-SECRET): %w", err)
}
secretEnv, err := waveappstore.BuildAppSecretEnv(appId, manifest, secretBindings)
if err != nil {
return nil, fmt.Errorf("failed to build secret environment (ERR-SECRET): %w", err)
}
if builderEnv == nil {
builderEnv = make(map[string]string)
}
for k, v := range secretEnv {
builderEnv[k] = v
}
cmd := exec.Command(appBinPath)
cmd.Env = append(os.Environ(), "TSUNAMI_CLOSEONSTDIN=1")
if wavebase.IsDevMode() {View on GitHub (pinned to a4447c1563)
Solutions
- Re-provision the app's secret bindings through the secrets UI/RPC
- Check the secrets store file for corruption and restore or reset bindings
- Verify the decryption key source (keychain) is accessible to the wave process
- If the app needs no secrets, ensure bindings are stored as an empty set rather than missing
Example fix
// before
// no bindings stored for app -> read fails
// after
waveappstore.WriteAppSecretBindings(appId, map[string]string{}) // initialize empty bindings Defensive patterns
Strategy: fallback
Validate before calling
_, err := waveappstore.ReadAppSecretBindings(appId)
if err != nil {
// initialize empty bindings so the read path succeeds
waveappstore.WriteAppSecretBindings(appId, map[string]string{})
} Try / catch
if err := runApp(appId); err != nil {
if strings.Contains(err.Error(), "ERR-SECRET") && strings.Contains(err.Error(), "secret bindings") {
// re-provision secrets via secrets UI/RPC
}
} Prevention
- Provision (even empty) bindings before first run
- Test keychain access after OS upgrades
- Avoid manual edits to the secrets store
When it happens
Trigger: ReadAppSecretBindings fails — secrets file absent, corrupted, unreadable, or undecryptable (e.g. keychain/encryption key changed between sessions).
Common situations: User never provisioned secrets but the code path still requires reading bindings; OS keychain access denied; secrets store migrated between wave versions; encryption key rotated.
Related errors
- failed to build secret environment (ERR-SECRET): %w
- path cannot start with ~, ., or ..
- invalid source path: %w
- required secret %q is not bound
- failed to get secret %q: %w
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/12be676f24cdfb26.
Report an issue: GitHub.