wavetermdev/waveterm · error

failed to get secret %q: %w

Error message

failed to get secret %q: %w

What it means

For each bound secret, BuildAppSecretEnv calls secretstore.GetSecret(boundSecretName). If the secret store itself returns an error (as opposed to a clean 'not exists'), the lookup is aborted and wrapped as 'failed to get secret %q'. This signals a malfunction of the secret store backend, not a missing binding.

Source

Thrown at pkg/waveappstore/waveappstore.go:828

		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
		}

		secretEnv[secretName] = secretValue
	}

	return secretEnv, nil
}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Inspect the wrapped %w error to identify the backend failure (access denied vs corruption)
  2. Unlock the OS keychain / start the secret service (gnome-keyring, keychain daemon) and retry
  3. Verify the bound key name is a valid store key (no stray whitespace or wrong key)
  4. Test the key directly with secretstore.GetSecret to reproduce outside BuildAppSecretEnv
  5. If the store file is corrupted, restore it from backup or re-enter the secrets

Example fix

// before
val, exists, err := secretstore.GetSecret(" myapp/api-key") // key has leading space -> backend error
// after
key := strings.TrimSpace("myapp/api-key")
val, exists, err := secretstore.GetSecret(key)
if err != nil { return fmt.Errorf("secret store unavailable: %w", err) }
Defensive patterns

Strategy: try-catch

Validate before calling

for _, bound := range bindings {
    if _, _, err := secretstore.GetSecret(strings.TrimSpace(bound)); err != nil {
        return fmt.Errorf("secret store precheck failed for %q: %w", bound, err)
    }
}

Type guard

func secretStoreHealthy(keys []string) bool {
    for _, k := range keys {
        if _, _, err := secretstore.GetSecret(k); err != nil { return false }
    }
    return true
}

Try / catch

env, err := waveappstore.BuildAppSecretEnv(appId, manifest, bindings)
if err != nil && strings.Contains(err.Error(), "failed to get secret") {
    return fmt.Errorf("secret store backend failure, check keychain/daemon: %w", err)
}

Prevention

When it happens

Trigger: secretstore.GetSecret returns a non-nil error: corrupted/locked store backend, keychain access denied (OS keychain prompt rejected), store file unreadable, or backend initialization failure while resolving the bound key name.

Common situations: OS keychain is locked or denied access to the process (Linux secret service not running, macOS Keychain prompt denied, Windows Credential Manager issue); the secret store file was manually edited and corrupted; running headless where the keychain daemon is unavailable.

Related errors


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