{"record":{"id":"95fdf9f91b93a5d5","repo":"Hmbown/CodeWhale","slug":"invalid-field-expected-an-otlp-nanosecond-integer-string","errorCode":null,"errorMessage":"Invalid ${field}: expected an OTLP nanosecond integer string.","messagePattern":"Invalid (.+?): expected an OTLP nanosecond integer string\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"pet/src/core/ingest.ts","lineNumber":117,"sourceCode":"  if ('boolValue' in a) return a.boolValue;\n  if ('doubleValue' in a) return a.doubleValue;\n  if ('intValue' in a) {\n    const n = Number(a.intValue);\n    return Number.isSafeInteger(n) ? n : String(a.intValue);\n  }\n  if ('bytesValue' in a) return a.bytesValue;\n  if ('arrayValue' in a) return list(obj(a.arrayValue).values).map(decodeAnyValue);\n  if ('kvlistValue' in a) return attributes(obj(a.kvlistValue).values);\n  return v;\n}\nexport function attributes(value: unknown): Obj {\n  if (!Array.isArray(value)) return obj(value);\n  return Object.fromEntries(value.filter(x => typeof x?.key === 'string').map(x => [x.key, decodeAnyValue(x.value)]));\n}\nfunction ns(v: unknown, field: string): bigint {\n  if (typeof v === 'number' && !Number.isSafeInteger(v)) throw new Error(`${field} lost precision: encode OTLP nanoseconds as a decimal string.`);\n  const s = String(v ?? '');\n  if (!/^\\d{1,20}$/.test(s) || BigInt(s) > 18446744073709551615n) throw new Error(`Invalid ${field}: expected an OTLP nanosecond integer string.`);\n  return BigInt(s);\n}\nfunction otelStatus(v: unknown): Status {\n  const c = obj(v).code;\n  return c === 2 || c === 'STATUS_CODE_ERROR' ? 'error' : c === 1 || c === 'STATUS_CODE_OK' ? 'success' : 'unknown';\n}\nfunction normalizedEvent(v: unknown, index: number): WhaleEvent {\n  const a = obj(v), id = str(a.id), traceId = str(a.traceId), name = str(a.name);\n  if (!id || !traceId || !name) throw new Error(`Record ${index + 1} requires nonempty id, traceId, and name.`);\n  if (a.schemaVersion !== undefined && a.schemaVersion !== 1) throw new Error(`Record ${index + 1}: unsupported schemaVersion ${a.schemaVersion}.`);\n  const startTime = number(a.startTime, 'startTime', false)!;\n  const endTime = number(a.endTime, 'endTime') ?? startTime;\n  if (endTime < startTime) throw new Error(`Record ${index + 1}: endTime precedes startTime.`);\n  if (a.category !== undefined && !CATEGORIES.includes(a.category)) throw new Error(`Unknown category \"${a.category}\". Use \"other\" plus subtype for extensions.`);\n  const allowed: Status[] = ['pending', 'running', 'success', 'error', 'unknown'];\n  if (a.status !== undefined && !allowed.includes(a.status)) throw new Error(`Record ${index + 1}: invalid status.`);\n  const at = obj(a.attributes);\n  return {","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/pet/src/core/ingest.ts#L99-L135","documentation":"The `ns` helper validates its input as 1-20 ASCII digits whose value fits in uint64 (<= 18446744073709551615) after converting via String(v) (pet/src/core/ingest.ts:117). Anything else — negative numbers, floats, non-numeric strings, values above uint64 max — throws.","triggerScenarios":"Passing a negative number, decimal string, empty value, or a nanosecond value exceeding 2^64-1 to the ns-validated timestamp fields during OTLP ingest.","commonSituations":"Timestamps serialized as ISO strings; float nanosecond values from clock math; signed 64-bit values from Go exporters overflowing uint64; empty string for a missing timestamp.","solutions":["Supply a plain decimal integer string within uint64 range","Convert ISO dates to unix nanoseconds before ingest","Check for negative or float values from your producer and fix its serialization"],"exampleFix":"// before\nstartTimeUnixNano: '2023-11-14T22:13:20Z'\n// after\nstartTimeUnixNano: '1700000000000000000'","handlingStrategy":"validation","validationCode":"const okNs=(v:unknown)=>/^\\d{1,20}$/.test(String(v??''))&&BigInt(String(v))<=18446744073709551615n;","typeGuard":"const isUint64String=(v:unknown): v is string => typeof v==='string'&&/^\\d{1,20}$/.test(v)&&BigInt(v)<=18446744073709551615n;","tryCatchPattern":"try { ingest(records); } catch (e) { if (/expected an OTLP nanosecond integer string/.test(e.message)) { /* convert ISO/negative/float values to uint64 decimal strings */ } else throw e; }","preventionTips":["Validate nanosecond fields against /^\\d{1,20}$/ at the boundary","Convert timestamps to unix nanos once, at the producer","Guard against signed/float clock values from exporters"],"tags":["otlp","timestamps","format","bigint"],"backgroundTag":"invalid-argument-format","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-22T16:17:23.217Z"}