{"record":{"id":"7e732022326f2e77","repo":"openzipkin/zipkin","slug":"trace-modelview-traceid-is-missing-a-timestamp","errorCode":null,"errorMessage":"Trace ${modelview.traceId} is missing a timestamp","messagePattern":"Trace (.+?) is missing a timestamp","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"zipkin-lens/src/zipkin/trace.js","lineNumber":266,"sourceCode":"    });\n  } else {\n    spanRow.left = 0;\n  }\n}\n\n// TODO: Revisit naming\nexport function detailedTraceSummary(root) {\n  const serviceNameToCount = {};\n  let queue = root.queueRootMostSpans();\n  const modelview = {\n    traceId: queue[0].span.traceId,\n    depth: 0,\n    spans: [],\n  };\n\n  const { timestamp, duration } = getTraceTimestampAndDuration(root);\n  if (!timestamp)\n    throw new Error(`Trace ${modelview.traceId} is missing a timestamp`);\n\n  while (queue.length > 0) {\n    let current = queue.shift();\n\n    // This is more than a normal tree traversal, as we are merging any server spans that share the\n    // same ID. When that's the case, we pull up any of their children as if they are our own.\n    const spansToMerge = [current.span];\n    const children = [];\n    current.children.forEach((child) => {\n      if (current.span.id === child.span.id) {\n        spansToMerge.push(child.span);\n        child.children.forEach((grandChild) => children.push(grandChild));\n      } else {\n        children.push(child);\n      }\n    });\n\n    // Pulling up children may affect our sort order. We re-sort to ensure rows are added in","sourceCodeStart":248,"sourceCodeEnd":284,"githubUrl":"https://github.com/openzipkin/zipkin/blob/878ce2a1fad54ca941d17fdcf2e1d924b148eb1f/zipkin-lens/src/zipkin/trace.js#L248-L284","documentation":"Thrown by zipkin-lens's detailedTraceSummary when getTraceTimestampAndDuration returns no timestamp for the trace. Like the traceSummary variant, the detailed (waterfall) model requires at least one span with a timestamp to establish the trace's absolute start; otherwise the trace cannot be rendered. This is the same invariant enforced at the detailed-view layer.","triggerScenarios":"Calling detailedTraceSummary(rootSpanNode) on a span tree where all spans lack a timestamp field — e.g. building the detailed view from a fixture or from data where timestamps were never set or were removed.","commonSituations":"Rendering the trace waterfall from spans produced by stub instrumentation without clocks; a custom span producer (e.g. log-to-trace converter) that omits timestamp; partial data after storage truncation.","solutions":["Guarantee the root/server spans include timestamp (microseconds) before sending them to Zipkin.","If converting from another format, populate timestamp from your event time field.","Validate the raw span list with a pre-check (some span has timestamp) before invoking detailedTraceSummary."],"exampleFix":"// before\nconst root = buildTree([{ traceId: 'a', id: 'a', name: 'root' }]);\ndetailedTraceSummary(root); // throws\n\n// after\nconst root = buildTree([{ traceId: 'a', id: 'a', name: 'root', timestamp: 1700000000000000 }]);\ndetailedTraceSummary(root);","handlingStrategy":"validation","validationCode":"const spans = collectSpans(root);\nif (!spans.some((s) => typeof s.timestamp === 'number')) return showError('trace missing timestamp');","typeGuard":"const renderableTrace = (spans) => spans.length > 0 && spans.some((s) => typeof s?.timestamp === 'number');","tryCatchPattern":null,"preventionTips":["Check for timestamps before building the detailed view; guard the UI entry point with the same predicate."],"tags":["zipkin","javascript","trace-data","timestamp"],"backgroundTag":null,"analyzedSha":"878ce2a1fad54ca941d17fdcf2e1d924b148eb1f","analyzedAt":"2026-08-14T15:17:09.895Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}