knadh/listmonk · error

failed to create Altcha challenge: %w

Error message

failed to create Altcha challenge: %w

What it means

GenerateChallenge wraps an error from the altcha library's Challenge call when creating a proof-of-work challenge for the Altcha CAPTCHA provider. Common inner causes are invalid configuration (bad HMAC key, non-positive complexity, bad expiry) or internal altcha failures. The challenge is the first step of the Altcha verify flow, so this error blocks form rendering.

Source

Thrown at internal/captcha/captcha.go:129

	return c.provider
}

// GenerateChallenge generates a challenge for the active provider.
// For hCaptcha, this returns empty string as challenges are generated client-side.
// For Altcha, this returns a JSON challenge.
func (c *Captcha) GenerateChallenge() (string, error) {
	switch c.provider {
	case ProviderAltcha:
		exp := time.Now().Add(5 * time.Minute)
		challenge, err := altcha.CreateChallenge(altcha.ChallengeOptions{
			Algorithm:  altcha.SHA256,
			MaxNumber:  int64(c.altcha.Complexity),
			SaltLength: 12,
			HMACKey:    c.altcha.HMACKey,
			Expires:    &exp,
		})
		if err != nil {
			return "", fmt.Errorf("failed to create Altcha challenge: %w", err)
		}

		challengeJSON, err := json.Marshal(challenge)
		if err != nil {
			return "", fmt.Errorf("failed to marshal Altcha challenge: %w", err)
		}

		return string(challengeJSON), nil
	case ProviderHCaptcha:
		// hCaptcha generates challenges client-side.
		return "", nil
	default:
		return "", fmt.Errorf("no captcha provider enabled")
	}
}

// Verify verifies a CAPTCHA response.
func (c *Captcha) Verify(token string) (error, bool) {

View on GitHub (pinned to 670c01717d)

Solutions

  1. Check the captcha/altcha configuration: ensure HMACKey is a non-empty secure secret and Complexity is a positive integer.
  2. Confirm the Expires timestamp passed to altcha.Challenge is in the future.
  3. Unwrap the error (%w) to see altcha's inner message and fix accordingly.
  4. Pin/verify the altcha library version matches the option fields used (MaxNumber, SaltLength, HMACKey, Expires).

Example fix

// before: zero-value config silently passed to altcha
// config: [captcha] provider="altcha" complexity=0 hmac_key=""
// after: fail fast at startup
if c.provider == ProviderAltcha && (c.altcha.HMACKey == "" || c.altcha.Complexity <= 0) {
  return errors.New("altcha provider requires non-empty HMACKey and positive Complexity")
}
Defensive patterns

Strategy: validation

Validate before calling

if c.provider == "altcha" {
  if c.altcha.HMACKey == "" {
    return errors.New("altcha hmac_key is required")
  }
  if c.altcha.Complexity <= 0 {
    return errors.New("altcha complexity must be positive")
  }
}

Type guard

func altchaConfigValid(cfg AltchaConfig) bool {
  return cfg.HMACKey != "" && cfg.Complexity > 0
}

Try / catch

challenge, err := captcha.GenerateChallenge(r.Context())
if err != nil {
  if strings.Contains(err.Error(), "failed to create Altcha challenge") {
    log.Error("altcha challenge generation failed", "err", err)
    http.Error(w, "captcha unavailable", http.StatusServiceUnavailable)
    return
  }
  http.Error(w, "internal error", http.StatusInternalServerError)
}

Prevention

When it happens

Trigger: Calling GenerateChallenge with c.provider == ProviderAltcha when altcha.Challenge fails — e.g. HMACKey is empty/invalid, Complexity is zero or negative, the Expires time is in the past, or the altcha dependency returns an unexpected error.

Common situations: Forgot to configure altcha.HMACKey in config; Complexity left at 0 after a config refactor; HMAC key mismatch later causing verification issues traced back here; upgrading the altcha library to a version with different Challenge options.

Related errors


AI-assisted analysis of knadh/listmonk@670c01717d (2026-09-01). Data as JSON: /api/errors/20b757082ff9cc5a. Report an issue: GitHub.