{"record":{"id":"38021798403c007c","repo":"Billionmail/BillionMail","slug":"at-least-one-domain-is-required","errorCode":null,"errorMessage":"at least one domain is required","messagePattern":"at least one domain is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/acme/cli.go","lineNumber":91,"sourceCode":"\tcli.VerifyType = \"http\"\n\tcli.DnsProvider = \"\"\n\tcli.DnsConfig = nil\n\treturn cli\n}\n\n/**\n * @brief Validate parameters\n * @return error\n */\nfunc (cli *AcmeCLI) Validate() error {\n\t// Check email\n\tif cli.Email == \"\" {\n\t\treturn fmt.Errorf(\"email is required\")\n\t}\n\n\t// Check domains\n\tif len(cli.Domains) == 0 {\n\t\treturn fmt.Errorf(\"at least one domain is required\")\n\t}\n\n\t// Check verification type\n\tif cli.VerifyType != \"http\" && cli.VerifyType != \"dns\" {\n\t\treturn fmt.Errorf(\"verification type must be either 'http' or 'dns'\")\n\t}\n\n\t// Check DNS provider if using DNS verification\n\tif cli.VerifyType == \"dns\" {\n\t\tif cli.DnsProvider == \"\" {\n\t\t\treturn fmt.Errorf(\"DNS provider is required for DNS verification\")\n\t\t}\n\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 {","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/acme/cli.go#L73-L109","documentation":"Parameter check in AcmeCLI.Validate: the Domains slice on the AcmeCLI instance is empty, so there is nothing to request a certificate for. Validate rejects this before invoking applyCommand, since a certificate order requires at least one SAN domain.","triggerScenarios":"AcmeCLI constructed with Domains == nil or len(Domains) == 0 (missing --domains flag, empty config list) then Validate/Apply is called.","commonSituations":"Flag parsing where --domains was forgotten; splitting an empty domains env var yields zero entries; programmatic use where a dynamic domain list ended up empty after filtering.","solutions":["Populate cli.Domains with at least one FQDN before Apply","Pass --domains example.com (comma-separated for multiple) on the command","Guard upstream: if len(domains)==0 skip issuance and log a config warning"],"exampleFix":"// before\ndomains := strings.Split(os.Getenv(\"CERT_DOMAINS\"), \",\") // empty env -> []\ncli := &AcmeCLI{Email: e, Domains: domains, VerifyType: \"http\"}\n// after\nif len(domains) == 0 || domains[0] == \"\" { log.Fatal(\"CERT_DOMAINS must list at least one domain\") }\ncli := &AcmeCLI{Email: e, Domains: domains, VerifyType: \"http\"}","handlingStrategy":"validation","validationCode":"if len(cli.Domains) == 0 {\n    return errors.New(\"at least one domain must be configured before issuing\")\n}\nfor _, d := range cli.Domains {\n    if strings.TrimSpace(d) == \"\" { return errors.New(\"blank entry in domain list\") }\n}","typeGuard":null,"tryCatchPattern":"if err := cli.Validate(); err != nil {\n    if strings.Contains(err.Error(), \"at least one domain\") {\n        log.Printf(\"no domains configured; check --domains flag / CERT_DOMAINS env\")\n    }\n    os.Exit(1)\n}","preventionTips":["Require the --domains flag at parse time","Filter domain lists before checking emptiness so empty-after-filter is surfaced","Sanity-check env/config sources for empty splits","Log the effective domain list before Apply for auditability"],"tags":["validation","acme","required-field"],"backgroundTag":"missing-required-argument","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"}