{"record":{"id":"01ddc6951ca100c8","repo":"wavetermdev/waveterm","slug":"required-secret-q-is-bound-to-q-which-does-not-e","errorCode":null,"errorMessage":"required secret %q is bound to %q which does not exist in secret store","messagePattern":"required secret %q is bound to %q which does not exist in secret store","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/waveappstore/waveappstore.go","lineNumber":833,"sourceCode":"\tfor secretName, secretMeta := range manifest.Secrets {\n\t\tboundSecretName, hasBinding := bindings[secretName]\n\n\t\tif !secretMeta.Optional && !hasBinding {\n\t\t\treturn nil, fmt.Errorf(\"required secret %q is not bound\", secretName)\n\t\t}\n\n\t\tif !hasBinding {\n\t\t\tcontinue\n\t\t}\n\n\t\tsecretValue, exists, err := secretstore.GetSecret(boundSecretName)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to get secret %q: %w\", boundSecretName, err)\n\t\t}\n\n\t\tif !exists {\n\t\t\tif !secretMeta.Optional {\n\t\t\t\treturn nil, fmt.Errorf(\"required secret %q is bound to %q which does not exist in secret store\", secretName, boundSecretName)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tsecretEnv[secretName] = secretValue\n\t}\n\n\treturn secretEnv, nil\n}\n","sourceCodeStart":815,"sourceCodeEnd":843,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/waveappstore/waveappstore.go#L815-L843","documentation":"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.","triggerScenarios":"Bindings map contains secretName -> boundSecretName, secretMeta.Optional is false, and secretstore.GetSecret(boundSecretName) reports the key does not exist.","commonSituations":"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.","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"],"exampleFix":"// before\nbindings := map[string]string{\"API_KEY\": \"myapp/api-key\"} // key missing in store\n// after\nsecretstore.SetSecret(\"myapp/api-key\", actualKeyValue) // or:\nbindings[\"API_KEY\"] = \"myapp/api-key-v2\" // point at the real stored key\nwaveappstore.WriteAppSecretBindings(appId, bindings)","handlingStrategy":"validation","validationCode":"for secretName, boundKey := range bindings {\n    if meta := manifest.Secrets[secretName]; meta != nil && !meta.Optional {\n        if _, exists, err := secretstore.GetSecret(boundKey); err == nil && !exists {\n            return fmt.Errorf(\"precheck: key %q missing for required secret %s\", boundKey, secretName)\n        }\n    }\n}","typeGuard":"func boundKeysExist(manifest *wshrpc.AppManifest, bindings map[string]string) bool {\n    for name, key := range bindings {\n        meta, ok := manifest.Secrets[name]\n        if ok && !meta.Optional {\n            if _, exists, err := secretstore.GetSecret(key); err != nil || !exists { return false }\n        }\n    }\n    return true\n}","tryCatchPattern":"env, err := waveappstore.BuildAppSecretEnv(appId, manifest, bindings)\nif err != nil && strings.Contains(err.Error(), \"does not exist in secret store\") {\n    return fmt.Errorf(\"dangling binding — re-store the secret or rebind: %w\", err)\n}","preventionTips":["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"],"tags":["go","secrets","configuration"],"backgroundTag":"secret-key-not-found","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}