{"record":{"id":"d80407b274e33ff7","repo":"amir20/dozzle","slug":"failed-to-send-to-cloud-w","errorCode":null,"errorMessage":"failed to send to cloud: %w","messagePattern":"failed to send to cloud: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/notification/dispatcher/cloud.go","lineNumber":94,"sourceCode":"\t}\n\n\tpayload, err := json.Marshal(notification)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to marshal notification: %w\", err)\n\t}\n\n\treq, err := http.NewRequestWithContext(ctx, http.MethodPost, c.URL, bytes.NewReader(payload))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create request: %w\", err)\n\t}\n\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\treq.Header.Set(\"User-Agent\", UserAgent)\n\treq.Header.Set(\"X-API-Key\", c.APIKey)\n\n\tresp, err := c.client.Do(req)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to send to cloud: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode == http.StatusTooManyRequests {\n\t\tretryAfter := defaultRetryAfter\n\t\tif ra := resp.Header.Get(\"Retry-After\"); ra != \"\" {\n\t\t\tif seconds, err := strconv.Atoi(ra); err == nil {\n\t\t\t\tretryAfter = time.Duration(seconds) * time.Second\n\t\t\t}\n\t\t}\n\t\tc.blockedUntil.Store(time.Now().Add(retryAfter).UnixNano())\n\t\tlog.Warn().\n\t\t\tStr(\"cloud\", c.Name).\n\t\t\tDur(\"retry_after\", retryAfter).\n\t\t\tMsg(\"rate limited by cloud, circuit breaker tripped\")\n\t\treturn fmt.Errorf(\"cloud rate limited, backing off for %s\", retryAfter)\n\t}\n","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/amir20/dozzle/blob/d9463cbe21874e44ab79db6fa63e746ca7d22928/internal/notification/dispatcher/cloud.go#L76-L112","documentation":"This wraps the error returned by the HTTP client's Do() call when the POST to the Dozzle Cloud /api/events endpoint fails at the transport level. It means no HTTP response was received: connection refused, DNS failure, TLS error, timeout (client timeout is 10s), or context cancellation.","triggerScenarios":"Calling CloudDispatcher.Send when the network is down, DNS cannot resolve the cloud host, the TLS handshake fails, the 10s client timeout expires, or ctx is cancelled mid-request.","commonSituations":"Container has no outbound internet access; corporate proxy/firewall blocks doligence.dozzle.dev; DNS misconfiguration in Docker networks; a custom DOLIGENCE_URL pointing at an unreachable host.","solutions":["Inspect the wrapped %w cause with errors.Unwrap or %v to identify connection vs timeout vs DNS","Verify outbound network/DNS from the Dozzle container (docker exec ... wget https://doligence.dozzle.dev)","Check the DOLIGENCE_URL env var points to a reachable host if overridden","Retry with backoff; transport errors are transient unless the endpoint is permanently blocked by firewall"],"exampleFix":"if err := d.Send(ctx, n); err != nil {\n    var netErr net.Error\n    if errors.As(err, &netErr) && netErr.Timeout() {\n        // retry with backoff\n    }\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"var nErr net.Error\nif errors.As(err, &nErr) && nErr.Timeout() {\n    // exponential backoff retry\n} else {\n    // check connectivity/DNS before retrying\n}","preventionTips":["Verify outbound internet/DNS from the container before enabling cloud notifications","Check firewall/proxy rules for the cloud endpoint","Set a sane DOLIGENCE_URL only when you control the target"],"tags":["network","http-client","timeout","notifications"],"backgroundTag":"http-request-failed","analyzedSha":"d9463cbe21874e44ab79db6fa63e746ca7d22928","analyzedAt":"2026-09-07T10:08:55.855Z","contentChangedAt":"2026-09-07T10:08:55.855Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}