{"record":{"id":"9588a4a45adfd474","repo":"wtfutil/wtf","slug":"cannot-store-secrets-wtf-secretstore-is-not-confi","errorCode":null,"errorMessage":"cannot store secrets: wtf.secretStore is not configured","messagePattern":"cannot store secrets: wtf\\.secretStore is not configured","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cfg/secrets.go","lineNumber":172,"sourceCode":"\tcred, err := client.Get(prog.runner, service)\n\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"get %v from %v: %w\", service, prog.store, err)\n\t}\n\n\treturn &Secret{\n\t\tService:  cred.ServerURL,\n\t\tSecret:   cred.Secret,\n\t\tUsername: cred.Username,\n\t\tStore:    prog.store,\n\t}, nil\n}\n\nfunc StoreSecret(globalConfig *config.Config, secret *Secret) error {\n\tprog := newProgram(globalConfig)\n\n\tif prog == nil {\n\t\treturn errors.New(\"cannot store secrets: wtf.secretStore is not configured\")\n\t}\n\n\tcred := &credentials.Credentials{\n\t\tServerURL: secret.Service,\n\t\tUsername:  secret.Username,\n\t\tSecret:    secret.Secret,\n\t}\n\n\t// docker-credential requires a username, but it isn't necessary for\n\t// all services. Use a default if a username was not set.\n\tif cred.Username == \"\" {\n\t\tcred.Username = \"default\"\n\t}\n\n\terr := client.Store(prog.runner, cred)\n\n\tif err != nil {\n\t\treturn fmt.Errorf(\"store %v: %w\", prog.store, err)","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/wtfutil/wtf/blob/bb838c1ccb0f0f3223690df44afdec663d622881/cfg/secrets.go#L154-L190","documentation":"StoreSecret saves a credential through an external secret-store program (e.g. pass, security/kc) configured under wtf.secretStore. If newProgram() cannot build that program wrapper — meaning no secret store is configured in the global config — storage cannot proceed and this error is returned.","triggerScenarios":"Calling StoreSecret (directly or via RenderIf secret rendering) with a config that lacks a wtf.secretStore section; the config file loads but the secretStore block was deleted/renamed; using defaults without configuring a store while a module tries to persist a secret.","commonSituations":"Fresh wtfutil installs where users add a module requiring secrets but never configure the secretStore; config migrations dropping the secretStore key; typo'd key name so the section is nil at runtime.","solutions":["Add a wtf.secretStore section to config.yml specifying the store program (e.g. type and command)","Verify the config key spelling (wtf.secretStore) matches the schema","Check newProgram()'s supported store types and configure one of them","Guard the calling code: only call StoreSecret when the secret store is configured"],"exampleFix":"// before\nwtf:\n  # no secretStore configured\n// after\nwtf:\n  secretStore:\n    type: keychain\n    prefix: wtfutil","handlingStrategy":"validation","validationCode":"if globalConfig == nil || globalConfig.Uint(\"wtf.secretStore\", nil) == nil /* section absent */ {\n    return errors.New(\"configure wtf.secretStore before storing secrets\")\n}","typeGuard":"func secretStoreConfigured(c *config.Config) bool {\n    return c != nil && c.Section(\"wtf\").HasKey(\"secretStore\")\n}","tryCatchPattern":"if err := cfg.StoreSecret(conf, secret); err != nil {\n    if strings.Contains(err.Error(), \"not configured\") {\n        return fmt.Errorf(\"add a wtf.secretStore section to config.yml: %w\", err)\n    }\n    return err\n}","preventionTips":["Add the secretStore section during initial setup, not later","Validate config.yml against the wtf schema on startup","Keep the exact key casing: wtf.secretStore","Document the required store type for your team's modules"],"tags":["go","config","secrets"],"backgroundTag":"missing-config-section","analyzedSha":"bb838c1ccb0f0f3223690df44afdec663d622881","analyzedAt":"2026-09-03T17:02:45.030Z","contentChangedAt":"2026-09-03T17:02:45.030Z","schemaVersion":2},"datasetVersion":"2026-09-11T00:17:11.886Z"}