amir20/dozzle · error
empty key received
Error message
empty key received
What it means
After successfully decoding the token response, cloudCallback requires a non-empty `key` field; this key is what dozzle stores to authenticate with the cloud service. An empty key means the exchange technically succeeded but produced no credential, so dozzle refuses it with a 500.
Solutions
- Verify your Dozzle Cloud account/subscription is active and an API key is provisioned.
- Re-run the cloud connect flow to request a fresh exchange.
- Check dozzle server logs for the `Empty key received` entry and contact support if the account is valid.
Example fix
// before
{"key":""}
// after
{"key":"abc123...","expiresAt":"2026-01-01T00:00:00Z"} Defensive patterns
Strategy: validation
Validate before calling
const data = await res.json();
if (!data.key) {
// stop: exchange returned no credential; verify account/subscription before retry
} Type guard
function hasKey(v: { key?: string }): v is { key: string } {
return typeof v.key === 'string' && v.key.length > 0;
} Prevention
- Keep the Dozzle Cloud subscription active and the API key provisioned.
- Re-run the connect flow rather than reusing stale state.
- Report persistent empty-key responses to support with server logs.
When it happens
Trigger: The cloud exchange endpoint returns 200 with valid JSON but `key` is "" or the field is absent, e.g. account not provisioned, subscription inactive, or a cloud-side bug returning a success envelope without a key.
Common situations: Dozzle Cloud subscription lapsed or not active for this account; API key revoked on the cloud side while old tokens still validate; mismatched cloud service version returning a new response shape.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- cloud search failed
- cloud dispatcher missing
- invalid credentials
- cloud: no API key configured
- cloud: alerts
AI-assisted analysis of amir20/dozzle@d9463cbe21 (2026-09-07).
Data as JSON: /api/errors/ca3045e9105f68d9.
Report an issue: GitHub.
Appendix: source
Thrown at internal/web/cloud.go:95
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(io.LimitReader(resp.Body, 1024))
log.Error().Int("status", resp.StatusCode).Str("body", string(body)).Msg("Token exchange failed")
http.Error(w, "token exchange failed", http.StatusInternalServerError)
return
}
var tokenResp exchangeTokenResponse
if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil {
log.Error().Err(err).Msg("Failed to decode token response")
http.Error(w, "failed to decode token response", http.StatusInternalServerError)
return
}
if tokenResp.Key == "" {
log.Error().Msg("Empty key received")
http.Error(w, "empty key received", http.StatusInternalServerError)
return
}
var expiresAt *time.Time
if tokenResp.ExpiresAt != nil {
parsed, err := time.Parse(time.RFC3339, *tokenResp.ExpiresAt)
if err != nil {
log.Warn().Err(err).Str("expiresAt", *tokenResp.ExpiresAt).Msg("Failed to parse expiresAt, ignoring")
} else {
expiresAt = &parsed
}
}
// Save cloud config (also creates the cloud dispatcher and broadcasts to agents)
cc := ¬ification.CloudConfig{
APIKey: tokenResp.Key,
Prefix: tokenResp.Prefix,
ExpiresAt: expiresAt,View on GitHub (pinned to d9463cbe21)