koala73/worldmonitor · error · Error
Umami volume is not ready: ${volume.status ?? 'unknown'}
Error message
Umami volume is not ready: ${volume.status ?? 'unknown'} What it means
evaluateUmamiStorage computes usage trends and projections for an Umami volume, but only makes sense when the volume is in the 'Ready' state. It throws when volume.status is anything else (or undefined, rendered as 'unknown'), because size/current-size samples for a non-Ready volume would produce misleading projections. The check runs after validating the timestamp, sizeMB, and currentSizeMB inputs.
Solutions
- Wait for the volume to reach status 'Ready' (poll or re-run the check later) before evaluating storage.
- If the volume is stuck non-Ready, investigate the provider volume state (attach errors, provisioning failures) and repair it.
- If status is missing from your data source, fix the scrape/mapping so volume.status is populated, then re-run.
Example fix
// before
evaluateUmamiStorage({ volume: { sizeMB: 1024, currentSizeMB: 512 }, samples, now });
// after
if (volume.status === 'Ready') {
evaluateUmamiStorage({ volume, samples, now });
} Defensive patterns
Strategy: validation
Validate before calling
if (volume?.status !== 'Ready') {
throw new Error(`defer storage evaluation; volume status=${volume?.status ?? 'unknown'}`);
}
evaluateUmamiStorage({ volume, samples, now }); Type guard
function isReadyVolume(volume) {
return typeof volume === 'object' && volume !== null && volume.status === 'Ready'
&& typeof volume.sizeMB === 'number' && volume.sizeMB > 0
&& typeof volume.currentSizeMB === 'number' && volume.currentSizeMB >= 0;
} Try / catch
try {
const result = evaluateUmamiStorage({ volume, samples, now });
} catch (e) {
if (e.message.startsWith('Umami volume is not ready')) scheduleRecheck(volume);
else throw e;
} Prevention
- Poll volume status until 'Ready' before running storage projections after create/resize.
- Alert on volumes stuck in non-Ready states for longer than a threshold.
- Ensure the status scrape pipeline never omits the status field.
When it happens
Trigger: Passing a volume object whose status is e.g. 'Pending', 'Attaching', 'Failed', or missing entirely, while still supplying valid sizeMB and currentSizeMB values.
Common situations: Running the storage check immediately after resizing/creating a volume before it finished provisioning, checking a volume stuck in a failed attach state, or scraping status from an API that omits the field.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15).
Data as JSON: /api/errors/6bba888cc3e1ace6.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/check-umami-storage.mjs:119
const identity = volumeIdentity(volume);
if (identity === null) throw new Error('Umami volume must have a stable identity');
const priorCapacityMB = finiteNonNegative(previousState?.capacityMB);
const sameVolume = previousState?.volumeIdentity === identity && priorCapacityMB === capacityMB;
const samples = (sameVolume ? normalizeSamples(previousState?.samples, nowMs) : [])
.filter((sample) => Date.parse(sample.sampledAt) !== nowMs);
samples.push({ sampledAt: new Date(nowMs).toISOString(), currentSizeMB });
return { version: 1, volumeIdentity: identity, capacityMB, samples };
}
export function evaluateUmamiStorage({ volume, samples = [], now = Date.now() }) {
const nowMs = timestampMs(now);
const capacityMB = finiteNonNegative(volume?.sizeMB);
const currentSizeMB = finiteNonNegative(volume?.currentSizeMB);
if (nowMs === null) throw new Error('Storage evaluation time must be a valid timestamp');
if (capacityMB === null || capacityMB <= 0) throw new Error('Umami volume sizeMB must be greater than zero');
if (currentSizeMB === null) throw new Error('Umami volume currentSizeMB must be a non-negative number');
if (volume.status !== 'Ready') throw new Error(`Umami volume is not ready: ${volume.status ?? 'unknown'}`);
const usageRatio = currentSizeMB / capacityMB;
const points = normalizeSamples(samples, nowMs)
.filter((sample) => Date.parse(sample.sampledAt) !== nowMs)
.map((sample) => ({ day: (Date.parse(sample.sampledAt) - nowMs) / DAY_MS, sizeMB: sample.currentSizeMB }));
points.push({ day: 0, sizeMB: currentSizeMB });
let growthMBPerDay = null;
let projectedHeadroomDays = null;
if (-points[0].day >= UMAMI_STORAGE_POLICY.minimumTrendSpanDays) {
const meanDay = points.reduce((sum, point) => sum + point.day, 0) / points.length;
const meanSizeMB = points.reduce((sum, point) => sum + point.sizeMB, 0) / points.length;
let covariance = 0;
let variance = 0;
for (const point of points) {
covariance += (point.day - meanDay) * (point.sizeMB - meanSizeMB);
variance += (point.day - meanDay) ** 2;
}View on GitHub (pinned to 7d06c8633d)