caddyserver/caddy · error
global options are ambiguous: local_certs is confusing when
Error message
global options are ambiguous: local_certs is confusing when combined with cert_issuer, because local_certs is also a specific kind of issuer
What it means
newBaseAutomationPolicyFromDefaults rejects the global options combination of issuers (from 'cert_issuer', possibly multiple) together with 'local_certs'. local_certs is itself sugar for the internal issuer, so specifying both makes the intended issuer list ambiguous; the adapter refuses to guess.
Source
Thrown at caddyconfig/httpcaddyfile/tlsapp.go:937
globalPreferredChains := options["preferred_chains"]
hasGlobalACMEDefaults := globalACMECA != nil || globalACMECARoot != nil || globalACMEDNS || globalACMEEAB != nil || globalPreferredChains != nil
// if there are no global options related to automation policies
// set, then we can just return right away
if !hasGlobalAutomationOpts && !hasGlobalACMEDefaults {
if always {
return new(caddytls.AutomationPolicy), nil
}
return nil, nil
}
ap := new(caddytls.AutomationPolicy)
if hasKeyType {
ap.KeyType = keyType.(string)
}
if hasIssuers && hasLocalCerts {
return nil, fmt.Errorf("global options are ambiguous: local_certs is confusing when combined with cert_issuer, because local_certs is also a specific kind of issuer")
}
if hasIssuers {
ap.Issuers = issuers.([]certmagic.Issuer)
} else if hasLocalCerts {
ap.Issuers = []certmagic.Issuer{new(caddytls.InternalIssuer)}
}
if hasGlobalACMEDefaults {
for i := range ap.Issuers {
if err := fillInGlobalACMEDefaults(ap.Issuers[i], options); err != nil {
return nil, fmt.Errorf("filling in global issuer defaults for issuer %d: %v", i, err)
}
}
}
if hasOCSPStapling {
ocspConfig := ocspStapling.(certmagic.OCSPConfig)View on GitHub (pinned to 50e54ee279)
Solutions
- Remove 'local_certs' if you want the explicit cert_issuer to apply.
- Or remove 'cert_issuer' if you want internal self-signed certs everywhere.
- To mix internal and public per site, drop both globals and use per-site 'tls internal' / 'tls issuer acme'.
Example fix
# before
{
local_certs
cert_issuer acme
}
# after
{
cert_issuer acme
} Defensive patterns
Strategy: validation
Validate before calling
grep -nE 'local_certs|cert_issuer' Caddyfile # both present => ambiguity
Prevention
- Choose one TLS issuance strategy globally; use per-site tls blocks for exceptions.
When it happens
Trigger: A global options block containing both 'local_certs' and 'cert_issuer <module> ...' (e.g. cert_issuer acme).
Common situations: Migrating a config from self-signed internal certs to ACME and leaving local_certs behind; copy-pasting a cert_issuer block into a template that already had local_certs.
Related errors
- filling in global issuer defaults for AP %d, issuer %d: %v
- acme_dns specified without DNS provider config, but no provi
- filling in global issuer defaults for issuer %d: %v
- consolidating TLS connection policies for server %d: %v
- applying global server options: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/5854716253f1d30e.
Report an issue: GitHub.