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
- Read json.detail from the Network tab response — it names the actual cause (e.g. 'Too many requests', 'Mail service not available').
- Check the backend notification/email configuration (application.yaml spring.mail.host, the notifier plugin) if detail mentions sending failure.
- If detail indicates rate limiting, throttle the send button via sendVerificationCode's countdown and respect Retry-After.
- Ensure the backend email-code endpoint is reachable and not returning 404 (path misconfiguration) which some proxies render as a detail-only body.
- 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
- Throttle the 'Send Code' button (60s countdown) to avoid rate-limit detail responses.
- Confirm the SMTP/notifier backend is configured before enabling email-code login.
- Cache the last error detail to avoid spamming the server on repeated clicks.
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
- json.errors[0]
- i18nResources.sendVerificationCodeFailed
- Cannot resolve shared dependency ${root} from ${resolutionBa
- Shared dependency ${root} resolved to ${packageJson.name ||
- problemDetail.comment.systemUsersOnly
AI-assisted analysis of halo-dev/halo@d2f5165f9c (2026-08-14).
Data as JSON: /api/errors/ad09c2a4e520d712.
Report an issue: GitHub.