hcengineering/platform · warning
Failed to send statistics
Error message
Failed to send statistics
What it means
This is a warning logged by the server's statistics/metrics reporting timer when an attempt to POST stats to the configured statsUrl fails. It is logged every second failure (errorToSend % 2 === 0) and includes the underlying error code (e.g. from undici), message, and cause. It indicates the metrics/telemetry endpoint is unreachable or rejecting requests; it does not affect core server functionality.
Source
Thrown at foundations/server/packages/core/src/stats.ts:108
} else {
metricsContext = new MeasureMetricsContext(serviceName, {}, {}, newMetrics())
}
const statsUrl = ops?.statsUrl ?? process.env.STATS_URL
let errorToSend = 0
if (statsUrl !== undefined) {
metricsContext.info('using stats url', { statsUrl, service: serviceName ?? '' })
const serviceId = encodeURIComponent(os.hostname() + '-' + serviceName)
let prev: Promise<void> | Promise<any> | undefined
const handleError = (err: any): void => {
errorToSend++
if (errorToSend % 2 === 0) {
const code = err?.code ?? err?.cause?.code
if (code !== 'UND_ERR_SOCKET') {
metricsContext.warn('Failed to send statistics', {
service: serviceName,
statsUrl,
code,
message: err?.message,
causeMessage: err?.cause?.message,
err
})
}
}
prev = undefined
}
const intTimer = setInterval(() => {
try {
if (prev !== undefined) {
// In case of high load, skip
return
}View on GitHub (pinned to 63e28dc964)
Solutions
- Verify the statsUrl configuration points to a reachable, healthy stats collector service
- Check network/firewall/DNS from the server host to the stats endpoint (curl the statsUrl)
- Inspect the logged code/causeMessage to identify the transport error (UND_ERR_SOCKET, ECONNREFUSED, etc.) and fix accordingly
- If the collector is intentionally absent, disable stats reporting in config instead of letting it fail repeatedly
- Upgrade undici/Node if errors are UND_ERR_SOCKET caused by known connection-reuse bugs
Example fix
// before (config) STATS_URL=http://stats-internal:4900/ingest // after (correct reachable collector or disabled) STATS_URL=http://stats-collector.monitoring.svc:4900/ingest # or STATS_ENABLED=false
Defensive patterns
Strategy: retry
Validate before calling
const ok = await fetch(statsUrl, { method: 'HEAD' }).then(r => r.ok).catch(() => false)
if (!ok) console.warn('stats endpoint unreachable, skipping report') Type guard
function hasErrorCode(err: unknown): err is { code: string } {
return typeof err === 'object' && err !== null && 'code' in err && typeof (err as any).code === 'string'
} Try / catch
try {
await sendStats()
} catch (err) {
const code = (err as any)?.code ?? (err as any)?.cause?.code
if (code !== 'UND_ERR_SOCKET') logger.warn('stats send failed', { code })
// swallow: stats loss is non-fatal
} Prevention
- Monitor the stats endpoint with an uptime probe
- Make stats reporting optional/disablable via config
- Log code + causeMessage (as the source does) to speed diagnosis
- Alert on sustained send failures rather than single blips
When it happens
Trigger: The intTimer periodic callback invokes the stats send (an HTTP fetch/undici request to statsUrl) and the promise rejects — e.g. DNS failure, connection refused/reset, UND_ERR_SOCKET, timeout, or non-2xx response from the stats collector.
Common situations: Stats collector service is down or misconfigured; statsUrl points to a wrong host/port in server config; network egress restrictions or firewall blocks the collector; transient socket errors under load (UND_ERR_SOCKET from undici).
Related errors
- "npm view" returned error code ${npmVersionSpawnResult.statu
- Unable to resolve version ${version} of package ${name}: ${e
- response.statusText
- "npm view" returned error code ${npmVersionSpawnResult.statu
- Failed to fetch config
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/4cb500670a8d6eaf.
Report an issue: GitHub.