ruvnet/ruflo · error · Error
Cannot compute baseline from empty readings
Error message
Cannot compute baseline from empty readings
What it means
AnomalyDetectionService.computeBaseline derives per-dimension mean and standard deviation from a window of telemetry readings and needs at least one reading to establish dimensionality (readings[0].vector.length). An empty window is rejected up front rather than producing NaN statistics.
Source
Thrown at v3/@claude-flow/plugin-iot-cognitum/src/domain/services/anomaly-detection-service.ts:46
export class AnomalyDetectionService {
private readonly config: AnomalyDetectionConfig;
private readonly baselines = new Map<string, TelemetryBaseline>();
constructor(config?: Partial<AnomalyDetectionConfig>) {
this.config = {
anomalyThreshold: config?.anomalyThreshold ?? 0.7,
quarantineThreshold: config?.quarantineThreshold ?? 0.9,
baselineWindowSize: config?.baselineWindowSize ?? 100,
};
}
/**
* Compute a baseline from a window of readings for a device.
* Calculates mean and standard deviation per vector dimension.
*/
computeBaseline(deviceId: string, readings: TelemetryReading[]): TelemetryBaseline {
if (readings.length === 0) throw new Error('Cannot compute baseline from empty readings');
const dim = readings[0].vector.length;
const n = readings.length;
// Compute mean
const mean = new Array<number>(dim).fill(0);
for (const r of readings) {
for (let i = 0; i < dim; i++) mean[i] += r.vector[i] / n;
}
// Compute standard deviation
const std = new Array<number>(dim).fill(0);
for (const r of readings) {
for (let i = 0; i < dim; i++) {
const diff = r.vector[i] - mean[i];
std[i] += (diff * diff) / n;
}
}View on GitHub (pinned to fa13ee4ad6)
Solutions
- Ingest at least one telemetry vector for the device before computing a baseline
- Guard the call: skip or defer baseline computation when readings.length === 0
- Verify the window bounds of the query include the device's actual telemetry range
Example fix
// before
const baseline = svc.computeBaseline(deviceId, await fetchReadings(deviceId, window)); // [] -> throws
// after
const readings = await fetchReadings(deviceId, window);
if (readings.length === 0) {
logger.info(`no readings yet for ${deviceId}; baseline deferred`);
} else {
const baseline = svc.computeBaseline(deviceId, readings);
} Defensive patterns
Strategy: validation
Validate before calling
const readings = await fetchReadings(deviceId, window);
if (readings.length === 0) {
return { status: 'deferred', reason: 'no readings in window' };
}
return svc.computeBaseline(deviceId, readings); Type guard
function hasReadings(rs: TelemetryReading[]): rs is [TelemetryReading, ...TelemetryReading[]] {
return rs.length > 0;
} Try / catch
try {
svc.computeBaseline(deviceId, readings);
} catch (e) {
if (e instanceof Error && e.message === 'Cannot compute baseline from empty readings') {
// defer baseline until telemetry arrives
} else throw e;
} Prevention
- Sequence onboarding as register, ingest, then baseline
- Log per-window reading counts in telemetry pipelines
- Alert on devices producing zero readings so baselines are never attempted on empty data
When it happens
Trigger: Calling computeBaseline with an empty readings array — typically a device that just registered and has no telemetry yet, or a time-window/baselineWindowSize query that matched zero readings.
Common situations: Baselining immediately after device onboarding before any ingest; querying a window that starts before the device's first telemetry timestamp; devices that were offline and accumulated no readings.
Related errors
- localCompute: no adapter for graphId=${input.graphId}
- Invalid completion type
- Router multimodal is enabled but LLM_ROUTER_MULTIMODAL_MODEL
- Routes config must be a flat array of routes
- Invalid route entry: ${JSON.stringify(r)}
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/6a394f832022a878.
Report an issue: GitHub.