{"record":{"id":"c101c16d45b256aa","repo":"Billionmail/BillionMail","slug":"dns-provider-credentials-are-required-for-dns-veri","errorCode":null,"errorMessage":"DNS provider credentials are required for DNS verification","messagePattern":"DNS provider credentials are required for DNS verification","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/acme/cli.go","lineNumber":122,"sourceCode":"\n\t\t// Check if DNS provider is supported\n\t\tsupportedProviders := []string{\"tencentcloud\", \"alidns\", \"cloudxns\", \"azuredns\", \"cloudflare\", \"godaddy\"}\n\t\tisSupported := false\n\t\tfor _, provider := range supportedProviders {\n\t\t\tif cli.DnsProvider == provider {\n\t\t\t\tisSupported = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif !isSupported {\n\t\t\treturn fmt.Errorf(\"unsupported DNS provider: %s, supported providers: %s\",\n\t\t\t\tcli.DnsProvider, strings.Join(supportedProviders, \", \"))\n\t\t}\n\n\t\t// Check DNS config\n\t\tif cli.DnsConfig == nil || len(cli.DnsConfig) == 0 {\n\t\t\treturn fmt.Errorf(\"DNS provider credentials are required for DNS verification\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\n/**\n * @brief Apply for certificate\n * @return certificatePath, privateKeyPath, error\n */\nfunc (cli *AcmeCLI) Apply() (string, string, error) {\n\t// Validate parameters\n\tif err := cli.Validate(); err != nil {\n\t\treturn \"\", \"\", err\n\t}\n\n\t// Create context\n\tctx := context.Background()","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/acme/cli.go#L104-L140","documentation":"When VerifyType is \"dns\", Validate also requires DnsConfig to be a non-empty map of provider credentials (API keys/tokens/secret ids). This error is returned when DnsConfig is nil or empty, meaning the ACME client could not authenticate to the DNS provider API.","triggerScenarios":"VerifyType=\"dns\" with a valid DnsProvider but DnsConfig nil/empty — credentials flag or config section omitted.","commonSituations":"Secrets managed separately and not injected into the config; rotation jobs that cleared the credentials map; users providing credentials as flags but never wiring them into DnsConfig.","solutions":["Populate cli.DnsConfig with the provider's required credentials (e.g. {\"api_key\": ...} for cloudflare, SecretId/SecretKey for alidns)","Load credentials from env/secret store before Apply and fail fast if empty","Pass credentials via the CLI's dns-config flag/JSON"],"exampleFix":"// before\ncli := &AcmeCLI{Email: e, Domains: d, VerifyType: \"dns\", DnsProvider: \"cloudflare\"} // no DnsConfig\n// after\ncli := &AcmeCLI{Email: e, Domains: d, VerifyType: \"dns\", DnsProvider: \"cloudflare\",\n  DnsConfig: map[string]string{\"api_key\": os.Getenv(\"CF_API_KEY\")}}","handlingStrategy":"validation","validationCode":"if cli.VerifyType == \"dns\" {\n    if len(cli.DnsConfig) == 0 { return errors.New(\"dns credentials missing\") }\n    required := []string{\"api_key\"} // adjust per provider\n    for _, k := range required {\n        if v, ok := cli.DnsConfig[k]; !ok || strings.TrimSpace(v) == \"\" {\n            return fmt.Errorf(\"dns credential %q missing\", k)\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"if err := cli.Validate(); err != nil {\n    if strings.Contains(err.Error(), \"credentials are required\") {\n        log.Printf(\"inject DNS API credentials from secret store before issuance\")\n    }\n    os.Exit(1)\n}","preventionTips":["Inject credentials from a secret manager at startup, not from hard-coded config","Fail fast on empty secret values rather than at issuance time","Rotate credentials and re-verify non-empty after rotation","Keep credentials keyed per provider and validate per-provider required keys"],"tags":["validation","acme","dns","credentials"],"backgroundTag":"missing-credentials","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}