{"record":{"id":"9e011acdd245c734","repo":"Hmbown/CodeWhale","slug":"invalid-pet-duration-native","errorCode":null,"errorMessage":"Invalid pet duration.","messagePattern":"Invalid pet duration\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"pet/ios/Resources/pet-native.js","lineNumber":1171,"sourceCode":"        this.sequence = packet.sequence;\n        if (previous === undefined || packet.sequence <= previous)\n            return;\n        return packet;\n    }\n}\nexports.PetLiveTape = PetLiveTape;\nconst order = (a, b) => a < b ? -1 : a > b ? 1 : 0;\nconst keyOf = (e) => JSON.stringify([e.traceId, e.id]);\nconst isContainer = (e) => e.attributes['whalesong.container'] === true\n    || e.attributes['codewhale.container'] === true;\n/** Compile a single trace. Unknown-duration spans provide onsets, not occupancy.\n * Updates of the same trace/id replace earlier snapshots rather than double count.\n * An endpoint onset gets its own bucket; intervals use [start, end). */\nfunction compilePetTelemetry(input, durationMs = 0, firstSequence = 0, originMs = 0) {\n    if (input.length > 250_000)\n        throw new Error('Pet input exceeds 250000 events.');\n    if (!Number.isFinite(durationMs) || durationMs < 0)\n        throw new Error('Invalid pet duration.');\n    if (!Number.isSafeInteger(firstSequence) || firstSequence < 0)\n        throw new Error('Invalid first pet bucket.');\n    if (!Number.isFinite(originMs))\n        throw new Error('Invalid pet clock origin.');\n    durationMs = Math.max(0, durationMs - originMs);\n    const unique = new Map();\n    const traces = new Set();\n    for (const e of input) {\n        if (e.schemaVersion !== 1 || !e.id || !e.traceId || !model_js_1.CATEGORIES.includes(e.category)\n            || !Number.isFinite(e.startTime) || !Number.isFinite(e.endTime)\n            || e.startTime < 0 || e.endTime < e.startTime || !e.attributes)\n            throw new Error('Invalid event-v1 pet input. Import through importTrace first.');\n        traces.add(e.traceId);\n        unique.set(keyOf(e), e);\n    }\n    if (traces.size > 1)\n        throw new Error('Select one trace for the pet.');\n    const parents = new Set([...unique.values()].filter(e => e.parentId).map(e => e.parentId));","sourceCodeStart":1153,"sourceCodeEnd":1189,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/pet/ios/Resources/pet-native.js#L1153-L1189","documentation":"compilePetTelemetry requires durationMs to be a finite, non-negative number of milliseconds; anything else (NaN, Infinity, negative) is rejected because bucket allocation is derived arithmetically from it. originMs is subtracted afterwards, so the raw value must still be valid on its own.","triggerScenarios":"Passing durationMs as NaN/Infinity/negative — e.g. computing it from an unset end timestamp (undefined - start = NaN), a failed Date parse, a negative elapsed due to clock skew, or passing seconds instead of milliseconds producing a wrong-but-finite value (that one won't throw; NaN/negative will).","commonSituations":"Clock skew between producer and consumer making end<start; uninitialized end-time fields; string durations ('1200') from JSON that slipped through; new Date('garbage').getTime().","solutions":["Coerce the duration before calling: Number.isFinite(d) && d >= 0, else clamp to 0.","Fix the upstream timestamp so end - start is a valid non-negative number of ms.","Sanitize JSON-sourced durations with Number(...) and reject NaN at parse time.","Normalize clock sources (use a single monotonic clock) to avoid skew-induced negatives."],"exampleFix":"// before\ncompilePetTelemetry(events, endTs - startTs);\n// after\nconst d = Number(endTs) - Number(startTs);\ncompilePetTelemetry(events, Number.isFinite(d) && d >= 0 ? d : 0, firstSequence, originMs);","handlingStrategy":"validation","validationCode":"const d = end - start;\nif (!Number.isFinite(d) || d < 0) throw new Error('bad duration'); // fix timestamps upstream\ncompilePetTelemetry(events, d, firstSequence, originMs);","typeGuard":"const isValidDuration = (d) => typeof d === 'number' && Number.isFinite(d) && d >= 0;","tryCatchPattern":"try { compilePetTelemetry(events, durationMs, firstSequence, originMs); }\ncatch (e) { if (e.message === 'Invalid pet duration.') { compilePetTelemetry(events, 0, firstSequence, originMs); } else throw e; }","preventionTips":["Compute durations from a single monotonic clock to avoid skew negatives.","Check timestamps are initialized before subtracting.","Coerce JSON-sourced durations with Number() and reject NaN at the boundary.","Clamp with Math.max(0, d) when a zero duration is acceptable."],"tags":["validation","duration","telemetry"],"backgroundTag":"invalid-argument-value","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-22T21:17:16.096Z"}