Billionmail/BillionMail · error

base URL not configured

Error message

base URL not configured

What it means

HttpGetSrc in public/common.go performs an HTTP GET and, for any status code outside 2xx (or <200), records an error formatted as 'http get error: %s' with resp.Status (e.g. '404 Not Found'). Note the function still proceeds to read the body; the error is returned with whatever body was read, so callers get a non-2xx response surfaced as a Go error.

Source

Thrown at core/internal/controller/campaign/campaign_v1_form.go:99

	if err = r.Session.Set("csrf_token", csrfToken); err != nil {
		csrfToken = ""
	}

	groups, _ := contact.GetAllGroups(ctx, "")

	err = r.Response.WriteTpl("subscription_form.html", g.Map{
		"Groups":    groups,
		"CSRFToken": csrfToken,
	})
	return
}

// sendConfirmationEmail sends a confirmation email to the newly subscribed user
func sendConfirmationEmail(ctx context.Context, email, name string) error {
	// Get the base domain to construct noreply email
	baseURL := domains.GetBaseURL()
	if baseURL == "" {
		return fmt.Errorf("base URL not configured")
	}

	// Extract domain from base URL
	domain := ""
	if u, err := url.Parse(baseURL); err == nil && u.Hostname() != "" {
		domain = u.Hostname()
	} else {
		// Fallback: try to get from environment
		if hostname, err := public.DockerEnv("BILLIONMAIL_HOSTNAME"); err == nil && hostname != "" {
			domain = hostname
		} else {
			return fmt.Errorf("unable to determine domain for noreply email")
		}
	}

	// Construct noreply email address
	noreplyEmail := fmt.Sprintf("noreply@%s", domain)

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Inspect resp.Status in the error to identify the concrete HTTP status and address it (fix URL, auth, or server)
  2. Verify the target URL is reachable (curl the endpoint) and correct any typos or port errors
  3. Add/refresh authentication credentials if the status is 401/403
  4. Enable redirect following or call the final URL directly for 3xx statuses; add retry/backoff for 5xx

Example fix

// before
body, err := public.HttpGetSrc(ctx, client, "http://host/old-endpoint")
// after
if body, err = public.HttpGetSrc(ctx, client, "https://host/new-endpoint"); err != nil {
	g.Log().Errorf(ctx, "GET failed: %v", err)
	return err
}
Defensive patterns

Strategy: try-catch

Validate before calling

req, _ := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if resp, err := client.Do(req); err == nil {
	resp.Body.Close()
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return fmt.Errorf("endpoint unhealthy: %s", resp.Status)
	}
}

Try / catch

body, err := public.HttpGetSrc(ctx, client, url)
if err != nil {
	var he *fmt.Errorf // inspect status embedded in message
	g.Log().Warningf(ctx, "GET %s failed: %v", url, err)
	if strings.Contains(err.Error(), "50") { // 5xx: retry with backoff
		return retryWithBackoff(url)
	}
	return err
}

Prevention

When it happens

Trigger: Any call through HttpGetSrc (directly or via HttpRequestTool, RequestUrl, HttpGetJson) where the remote server returns 1xx, 3xx (unfollowed redirects), 4xx or 5xx — dead URL, auth failure, server error, redirect to a non-followed location.

Common situations: Calling an internal API with an expired token (401/403), fetching a moved endpoint (404), a downstream service being down (502/503), or a server returning 3xx with redirects disabled.

Related errors


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