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

  1. Re-provision the app's secret bindings through the secrets UI/RPC
  2. Check the secrets store file for corruption and restore or reset bindings
  3. Verify the decryption key source (keychain) is accessible to the wave process
  4. 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

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


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/12be676f24cdfb26. Report an issue: GitHub.