{"record":{"id":"6d85210de70bf2f9","repo":"caddyserver/caddy","slug":"url-is-required","errorCode":null,"errorMessage":"URL is required","messagePattern":"URL is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddytls/certmanagers.go","lineNumber":124,"sourceCode":"\t// (No Content). Error statuses will indicate that the manager is\n\t// capable of providing a certificate but was unable to.\n\tURL string `json:\"url,omitempty\"`\n\n\tctx context.Context\n}\n\n// CaddyModule returns the Caddy module information.\nfunc (hcg HTTPCertGetter) CaddyModule() caddy.ModuleInfo {\n\treturn caddy.ModuleInfo{\n\t\tID:  \"tls.get_certificate.http\",\n\t\tNew: func() caddy.Module { return new(HTTPCertGetter) },\n\t}\n}\n\nfunc (hcg *HTTPCertGetter) Provision(ctx caddy.Context) error {\n\thcg.ctx = ctx\n\tif hcg.URL == \"\" {\n\t\treturn fmt.Errorf(\"URL is required\")\n\t}\n\treturn nil\n}\n\nfunc (hcg HTTPCertGetter) GetCertificate(ctx context.Context, hello *tls.ClientHelloInfo) (*tls.Certificate, error) {\n\tsigs := make([]string, len(hello.SignatureSchemes))\n\tfor i, sig := range hello.SignatureSchemes {\n\t\tsigs[i] = fmt.Sprintf(\"%x\", uint16(sig)) // you won't believe what %x uses if the val is a Stringer\n\t}\n\tsuites := make([]string, len(hello.CipherSuites))\n\tfor i, cs := range hello.CipherSuites {\n\t\tsuites[i] = fmt.Sprintf(\"%x\", cs)\n\t}\n\n\tparsed, err := url.Parse(hcg.URL)\n\tif err != nil {\n\t\treturn nil, err\n\t}","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddytls/certmanagers.go#L106-L142","documentation":"Returned by HTTPCertGetter.Provision (the tls.get_certificate.http module, i.e. 'get_certificate http <url>' in a Caddyfile) when the URL field is empty. The module fetches a certificate bundle over HTTP at handshake time, so an endpoint is mandatory; provisioning fails fast rather than letting every handshake fail later.","triggerScenarios":"Configuring get_certificate http with no URL argument, or JSON config where tls.get_certificate.http has an empty/missing \"url\" key. In Caddyfile syntax: 'get_certificate http' with the URL line missing or mistyped as a subdirective.","commonSituations":"Hand-written Caddyfile omits the URL; JSON config built programmatically leaves the field empty; a template/automation pipeline that was supposed to inject the URL produced an empty string.","solutions":["Add the URL: 'get_certificate http https://certs.example.com/certs' in the Caddyfile","If using JSON, ensure the module object has a non-empty \"url\" value","Run 'caddy adapt --config Caddyfile --adapter caddyfile' to confirm the URL survives adaptation","Check for typos that make the URL parse as a block instead of an argument"],"exampleFix":"# before\nget_certificate http\n\n# after\nget_certificate http https://certs.example.com/certs","handlingStrategy":"validation","validationCode":"# Adapt + inspect before running:\ncaddy adapt --config Caddyfile --adapter caddyfile 2>/dev/null | jq '.apps.tls.certificates.get_certificate // empty'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat get_certificate http as requiring exactly one argument; add a config lint step that rejects the directive with no URL","Use 'caddy validate --config <file>' in CI for every config change","If generating configs programmatically, fail the generator when the URL variable is empty"],"tags":["caddy","tls","certificates","configuration","http"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}