Billionmail/BillionMail · error

Failed to set HTTP verification: {}

Error message

Failed to set HTTP verification: {}

What it means

ApplySSLWithExistingServer configures a lego ACME client to solve the HTTP-01 challenge by registering a custom provider bound to 127.0.0.1:60880 via client.Challenge.SetHTTP01Provider. The error wraps any failure returned by lego when installing that provider. In lego this call essentially cannot fail for the built-in http01.ProviderServer, so hitting it indicates a programming bug, a nil client, or a forked/modified lego version whose SetHTTP01Provider performs extra validation.

Source

Thrown at core/internal/service/acme/acme.go:401

	// Get configuration
	config := GetConfig(myUser)
	if config == nil {
		return "", "", errors.New(public.LangCtx(ctx, "Failed to get configuration"))
	}

	client, err := lego.NewClient(config)
	if err != nil {
		return "", "", errors.New(public.LangCtx(ctx, "Failed to create ACME client: {}", err.Error()))
	}

	// Set verification method
	if vtype == "http" {
		// Assume the HTTP server is already running and properly configured
		// to handle the challenge requests
		err = client.Challenge.SetHTTP01Provider(http01.NewProviderServer("127.0.0.1", "60880"))
		if err != nil {
			return "", "", errors.New(public.LangCtx(ctx, "Failed to set HTTP verification: {}", err.Error()))
		}
	} else if vtype == "dns" && dnsProvider != "" {
		// Set DNS verification - same as in the standard ApplySSL function
		switch dnsProvider {
		case "tencentcloud":
			err = SetDnsTencentcloud(ctx, client, dnsProviderToken)
			if err != nil {
				return "", "", errors.New(public.LangCtx(ctx, "Failed to set Tencent Cloud DNS verification: {}", err.Error()))
			}
		case "alidns":
			err = SetDnsAliyun(ctx, client, dnsProviderToken)
			if err != nil {
				return "", "", errors.New(public.LangCtx(ctx, "Failed to set Alibaba Cloud DNS verification: {}", err.Error()))
			}
		case "cloudxns":
			err = SetDnsCloudxns(ctx, client, dnsProviderToken)
			if err != nil {
				return "", "", errors.New(public.LangCtx(ctx, "Failed to set CloudXNS DNS verification: {}", err.Error()))

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Inspect the wrapped err.Error() in the message; if it is empty or nil-related, verify the lego ACME client is constructed with a valid user private key before ApplySSLWithExistingServer is called
  2. Pin lego to the version upstream BillionMail was built against (go.mod) so SetHTTP01Provider matches the expected no-error behavior
  3. If running custom challenge logic, ensure the HTTP server actually listens on 127.0.0.1:60880 before requesting the certificate, since the challenge will fail later otherwise

Example fix

// before
client, err := lego.NewClient(lego.NewConfig())
err = client.Challenge.SetHTTP01Provider(http01.NewProviderServer("127.0.0.1", "60880"))
// after
client, err := lego.NewClient(lego.NewConfigForUser(myUser)) // valid key loaded
if err != nil { return "", "", err }
err = client.Challenge.SetHTTP01Provider(http01.NewProviderServer("127.0.0.1", "60880"))
Defensive patterns

Strategy: try-catch

Validate before calling

if client == nil || client.Challenge == nil {
    return fmt.Errorf("ACME client not initialized before SetHTTP01Provider")
}
// also ensure the challenge port is free:
if ln, err := net.Listen("tcp", "127.0.0.1:60880"); err != nil {
    return fmt.Errorf("port 60880 already in use: %w", err)
} else { ln.Close() }

Type guard

func acmeClientReady(c *lego.Client) bool { return c != nil && c.Challenge != nil }

Try / catch

cert, _, err := ApplySSLWithExistingServer(ctx, ...)
if err != nil {
    if strings.Contains(err.Error(), "Failed to set HTTP verification") {
        log.Printf("challenge provider setup failed: %v", err) // inspect lego cause
    }
    return err
}

Prevention

When it happens

Trigger: Calling ApplySSLWithExistingServer (via Apply, StartRenew, ApplyLetsEncryptCertWithHttp, or ApplyConsoleCert) with vtype == "http" while client.Challenge is nil/nil-initialized, or using a lego version where SetHTTP01Provider returns an error.

Common situations: Custom builds of lego with extra provider validation; a client constructed incorrectly (missing user key so Challenge chain misbehaves); copy-pasted code that nils out the Challenge map before this call.

Related errors


AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05). Data as JSON: /api/errors/7ca4b5194f1d8b95. Report an issue: GitHub.