Billionmail/BillionMail · error

failed to restart dovecot container: %v

Error message

failed to restart dovecot container: %v

What it means

restartDovecot wraps any failure from the Docker API call that restarts the Dovecot container (consts.SERVICES.Dovecot). The underlying Docker error (container missing, daemon unreachable, API timeout) is preserved via %v. Callers SetSSL, SetSNI and SetDovecotSSL surface it when certificate/SNI changes require the mail service to reload.

Source

Thrown at core/internal/service/mail_service/certificate.go:457

	}
	return config + "\n" + key + " = " + value
}

// restartPostfix restarts Postfix service
func (c *Certificate) restartPostfix() error {
	// Restart Postfix container
	if err := c.dockerApiClient().RestartContainerByName(context.Background(), consts.SERVICES.Postfix); err != nil {
		return fmt.Errorf("failed to restart postfix container: %v", err)
	}

	return nil
}

// restartDovecot restarts Dovecot service
func (c *Certificate) restartDovecot() error {
	// Restart Dovecot container
	if err := c.dockerApiClient().RestartContainerByName(context.Background(), consts.SERVICES.Dovecot); err != nil {
		return fmt.Errorf("failed to restart dovecot container: %v", err)
	}

	return nil
}

// GetSSLStatus checks SSL certificate status
func (c *Certificate) GetSSLStatus(domain string) (bool, error) {
	// Check Postfix certificate
	csrPath := filepath.Join(consts.SSL_PATH, domain, "/fullchain.pem")
	ketPath := filepath.Join(consts.SSL_PATH, domain, "/privkey.pem")

	return c.checkCertificateFiles(csrPath, ketPath), nil
}

// GetSSLInfo retrieves SSL certificate information
func (c *Certificate) GetSSLInfo(domain string) (certInfo v1.CertInfo, err error) {
	// First try to get certificate from database (acme managed certificates)

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Verify the dovecot container is running: `docker ps | grep dovecot`; start it if missing (`docker compose up -d dovecot`).
  2. Check Docker daemon health and that the API client's endpoint/socket is reachable (`docker info`, socket permissions).
  3. Confirm consts.SERVICES.Dovecot matches the actual container name in your deployment.
  4. Retry SetSSL/SetSNI after the container is healthy; check underlying %v detail for the specific Docker error.

Example fix

// before
certInfo, err := GetSSLInfo(ctx)
if err != nil { log.Fatal(err) }
// after
certInfo, err := GetSSLInfo(ctx)
if err != nil {
    if strings.Contains(err.Error(), "failed to restart dovecot container") {
        log.Printf("dovecot restart failed, check docker: %v", err)
    }
    log.Fatal(err)
}
Defensive patterns

Strategy: retry

Validate before calling

out, err := exec.Command("docker", "ps", "--format", "{{.Names}}").Output()
if err != nil || !strings.Contains(string(out), "dovecot") {
    return errors.New("dovecot container not running; start it before changing SSL settings")
}

Try / catch

err := cert.SetSSL(ctx, domain, certPem, keyPem)
if err != nil {
    if strings.Contains(err.Error(), "failed to restart dovecot container") {
        time.Sleep(5 * time.Second)
        err = cert.SetSSL(ctx, domain, certPem, keyPem) // bounded retry
    }
    return err
}

Prevention

When it happens

Trigger: Calling SetSSL, SetSNI, or SetDovecotSSL when the Docker daemon is down, the dovecot container does not exist (never started, renamed, or removed), or RestartContainerByName times out.

Common situations: Deploying on a host where the container is named differently than consts.SERVICES.Dovecot expects; Docker daemon restarted/not running; resource exhaustion making the restart hang; docker socket permission denied for the BillionMail process.

Related errors


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