halo-dev/halo · error · Error

json.detail

Error message

json.detail

What it means

Sibling branch in the same email-code login error cascade. The backend returned a non-2xx ProblemDetail body that has a `detail` string but no `errors` array. Spring populates `detail` for generic problem failures (e.g. rate-limited, email service unavailable, internal error) where there is no single field to blame. The detail text is re-thrown as the Error message.

Source

Thrown at application/src/main/resources/templates/login_email-code.html:71

          throw new Error(/*[[#{form.emailCode.send.emptyValidation}]]*/ "");
        }

        const response = await fetch("/login/email-code/send", {
          method: "POST",
          body: JSON.stringify({ email: email }),
          headers: {
            "Content-Type": "application/json",
            [headerName]: token,
          },
        });

        if (!response.ok) {
          const json = await response.json();
          if (json.errors && json.errors.length) {
            throw new Error(json.errors[0]);
          }
          if (json.detail) {
            throw new Error(json.detail);
          }
          throw new Error(i18nResources.sendVerificationCodeFailed);
        }

        return response;
      }

      const emailCodeSendButton = document.getElementById("emailCodeSendButton");
      sendVerificationCode(emailCodeSendButton, sendRequest);
    });
  </script>
</div>

View on GitHub (pinned to d2f5165f9c)

Solutions

  1. Read json.detail from the Network tab response — it names the actual cause (e.g. 'Too many requests', 'Mail service not available').
  2. Check the backend notification/email configuration (application.yaml spring.mail.host, the notifier plugin) if detail mentions sending failure.
  3. If detail indicates rate limiting, throttle the send button via sendVerificationCode's countdown and respect Retry-After.
  4. Ensure the backend email-code endpoint is reachable and not returning 404 (path misconfiguration) which some proxies render as a detail-only body.
  5. Tail backend logs around the timestamp of the failing request for the underlying exception.

Example fix

// before
if (json.detail) {
  throw new Error(json.detail);
}
// after — guard for non-string detail and prefer detail over a raw object dump
if (typeof json.detail === "string" && json.detail.trim()) {
  throw new Error(json.detail);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-flight checks that avoid common detail-only failures
function canSendEmailCode(lastSentAt) {
  // Respect client-side rate limiting to avoid 'Too many requests' detail
  const MIN_INTERVAL_MS = 60_000;
  return !lastSentAt || Date.now() - lastSentAt > MIN_INTERVAL_MS;
}

Type guard

// RFC 7807 ProblemDetail with a string detail and no errors array
function hasProblemDetail(body: unknown): body is { detail: string } {
  return (
    typeof body === "object" && body !== null &&
    typeof (body as any).detail === "string" &&
    (!Array.isArray((body as any).errors) || (body as any).errors.length === 0)
  );
}

Try / catch

try {
  const response = await sendRequest();
  // success path
} catch (e) {
  // e.message is the server's json.detail — map known details to localized copy
  const msg = e instanceof Error ? e.message : "";
  if (/too many/i.test(msg)) showRateLimitNotice();
  else showError(msg || i18nResources.sendVerificationCodeFailed);
}

Prevention

When it happens

Trigger: The /login/email-code/send call fails with a ProblemDetail whose `errors` array is absent/empty but `detail` is set. This happens on: email-code send rate limiting (too many codes requested), the SMTP/notifier backend being down or misconfigured, the email address not matching a known user when enumeration protection is disabled, or a 500 from the notification service.

Common situations: SMTP/mail sender not configured in application.yaml (spring.mail.* missing) so the backend returns a problem detail; hitting the per-session/per-email rate limit on code sending; a plugin implementing the verification-code extension throws a business exception that Spring maps to a ProblemDetail with detail only; network blip causing a gateway 5xx that Spring Boot renders with a detail field.

Related errors


AI-assisted analysis of halo-dev/halo@d2f5165f9c (2026-08-14). Data as JSON: /api/errors/ad09c2a4e520d712. Report an issue: GitHub.