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

  1. Re-store the secret under the bound key name (e.g. secretstore.SetSecret(boundSecretName, value))
  2. Or update the binding via WriteAppSecretBindings to point at the correct existing key
  3. Verify the exact key name in the store (watch for typos, case, and namespace prefixes)
  4. 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 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


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