{"record":{"id":"9a715f300a9cbbd2","repo":"wavetermdev/waveterm","slug":"required-secret-q-is-not-bound","errorCode":null,"errorMessage":"required secret %q is not bound","messagePattern":"required secret %q is not bound","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/waveappstore/waveappstore.go","lineNumber":819,"sourceCode":"\treturn nil\n}\n\nfunc BuildAppSecretEnv(appId string, manifest *wshrpc.AppManifest, bindings map[string]string) (map[string]string, error) {\n\tif manifest == nil {\n\t\treturn make(map[string]string), nil\n\t}\n\n\tif bindings == nil {\n\t\tbindings = make(map[string]string)\n\t}\n\n\tsecretEnv := make(map[string]string)\n\n\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","sourceCodeStart":801,"sourceCodeEnd":837,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/waveappstore/waveappstore.go#L801-L837","documentation":"BuildAppSecretEnv builds the environment variable map for an app by iterating manifest.Secrets. If a secret is declared non-optional (secretMeta.Optional == false) and the bindings map has no entry for it, the function fails fast with 'required secret %q is not bound'. The library refuses to launch apps whose required configuration is incomplete.","triggerScenarios":"Calling BuildAppSecretEnv (via runBuilderApp or GetStatus) with a manifest that declares a required secret while the bindings map returned by ReadAppSecretBindings lacks a key for that secret name.","commonSituations":"App was installed/upgraded to a version whose manifest added a new required secret; user never ran the binding command for that secret; secret name typo in the bindings file; bindings file was reset/emptied.","solutions":["Add a binding for the named secret via WriteAppSecretBindings (e.g. {\"SECRET_NAME\": \"store-key\"})","Check the manifest's Secrets section for the exact secret name and use it verbatim (case-sensitive)","If the secret is genuinely unnecessary, update/patch the manifest to mark it optional","Re-read bindings with ReadAppSecretBindings to confirm what is currently bound"],"exampleFix":"// before\nbindings, _ := waveappstore.ReadAppSecretBindings(appId) // missing \"API_KEY\"\nenv, err := waveappstore.BuildAppSecretEnv(appId, manifest, bindings)\n// after\nbindings[\"API_KEY\"] = \"myapp/api-key\" // bind required secret to a store key\nerr := waveappstore.WriteAppSecretBindings(appId, bindings)\nenv, err := waveappstore.BuildAppSecretEnv(appId, manifest, bindings)","handlingStrategy":"validation","validationCode":"bindings, err := waveappstore.ReadAppSecretBindings(appId)\nif err != nil { return err }\nfor name, meta := range manifest.Secrets {\n    if !meta.Optional {\n        if _, ok := bindings[name]; !ok {\n            return fmt.Errorf(\"precheck: required secret %s unbound\", name)\n        }\n    }\n}","typeGuard":"func allRequiredSecretsBound(manifest *wshrpc.AppManifest, bindings map[string]string) bool {\n    for name, meta := range manifest.Secrets {\n        if !meta.Optional {\n            if _, ok := bindings[name]; !ok { return false }\n        }\n    }\n    return true\n}","tryCatchPattern":"env, err := waveappstore.BuildAppSecretEnv(appId, manifest, bindings)\nif err != nil && strings.Contains(err.Error(), \"is not bound\") {\n    return fmt.Errorf(\"app %s misconfigured: %w (run the binding command)\", appId, err)\n}","preventionTips":["After app upgrades, diff the new manifest's Secrets against current bindings","Bind secrets immediately after install, before first run","Keep a record of each app's required secret names","Use exact, case-sensitive secret names from the manifest"],"tags":["go","configuration","secrets"],"backgroundTag":"required-secret-not-bound","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}