Skip to content

Conversation

@jamiedavenport
Copy link

@jamiedavenport jamiedavenport commented Oct 20, 2025

Before taking a look at how Start can automatically instrument applications with OpenTelemetry I wanted to create a simple example with manual instrumentation.

This is a copy/paste of react/start-basic with:

  • docker-compose.yml that runs Jaeger.
  • otel.ts that inits the SDK.
  • Basic tracing

Next Steps

  1. Keep updating the example which might be useful for users in the meantime (before automatic instrumentation)
  2. Open an RFC to discuss the API
  3. Incrementally remove the manual work from the example

Summary by CodeRabbit

  • New Features
    • Added a new React example project demonstrating OpenTelemetry integration for distributed tracing and request monitoring, including a local tracing backend with visualization tools, routing, data fetching, and error handling patterns.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 20, 2025

Walkthrough

This PR adds a complete new example project (examples/react/start-otel) demonstrating TanStack Router and React Start with OpenTelemetry tracing integration. It includes route definitions, components, utilities, Docker Compose setup for Jaeger, and build configuration.

Changes

Cohort / File(s) Summary
Configuration & Build Tools
.gitignore, .prettierignore, .vscode/settings.json, docker-compose.yml, package.json, postcss.config.mjs, tailwind.config.mjs, tsconfig.json, vite.config.ts
Project configuration, dependency management, build tooling for Vite, Tailwind CSS, TypeScript, and VSCode; Docker Compose service for Jaeger tracing UI and OTLP collection
OpenTelemetry Tracing
src/otel.ts, src/utils/tracer.ts
Initialize and export OpenTelemetry Node.js SDK with OTLP trace exporter; provide tracer utility for instrumentation
Router & Root Layout
src/router.tsx, src/routes/__root.tsx, src/routeTree.gen.ts
Router factory with error/not-found boundaries; root route with global head metadata, navigation shell, and devtools; generated route tree with all route definitions and type mappings
Route Components & Layouts
src/routes/_pathlessLayout.tsx, src/routes/_pathlessLayout/_nested-layout.tsx, src/routes/_pathlessLayout/_nested-layout/route-a.tsx, src/routes/_pathlessLayout/_nested-layout/route-b.tsx, src/routes/index.tsx
Layout and nested route definitions for demonstrating TanStack Router file-based routing and nested layouts
API Routes
src/routes/api/users.ts, src/routes/api/users.$userId.ts, src/routes/customScript[.]js.ts
Server-side API handlers for fetching users with middleware and tracing; custom script serving
Page Routes
src/routes/users.tsx, src/routes/users.index.tsx, src/routes/users.$userId.tsx, src/routes/posts.tsx, src/routes/posts.index.tsx, src/routes/posts.$postId.tsx, src/routes/posts_.$postId.deep.tsx, src/routes/deferred.tsx, src/routes/redirect.tsx
Page routes for browsing users and posts with dynamic parameters, deferred loading, and redirects
Error & Boundary Components
src/components/DefaultCatchBoundary.tsx, src/components/NotFound.tsx, src/components/PostError.tsx, src/components/UserError.tsx
Error boundary and not-found fallback components for error handling
Utilities & Server Functions
src/utils/users.tsx, src/utils/posts.tsx, src/utils/seo.ts, src/utils/loggingMiddleware.tsx
Type definitions, server functions for data fetching, SEO meta tag helpers, and client-server logging middleware
Styling & Assets
src/styles/app.css, public/site.webmanifest
Global Tailwind CSS with theme and dark mode support; PWA manifest file
Server Entry & Documentation
src/server.ts, README.md
Server request handler with OpenTelemetry tracing instrumentation; project documentation and setup guide

Sequence Diagram

sequenceDiagram
    participant Client
    participant OTel as OpenTelemetry
    participant Server
    participant Jaeger as Jaeger Collector
    
    rect rgb(200, 220, 255)
    Note over Client,Jaeger: Request with Tracing
    Client->>Server: HTTP Request
    Server->>OTel: startActiveSpan (method + path)
    Server->>OTel: setAttributes (http.method, http.url, route)
    end
    
    rect rgb(220, 240, 220)
    Note over Server: Route Processing
    Server->>Server: Load route data / fetch API
    Server->>Server: Handle request
    end
    
    rect rgb(200, 220, 255)
    Note over Client,Jaeger: Tracing Completion
    Server->>OTel: setStatus (OK)
    OTel->>Jaeger: Export span
    Server->>Client: HTTP Response
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

While the PR introduces ~40 new files totaling substantial code, the changes follow consistent, repetitive patterns (route definitions, configuration files, utility functions) that are relatively straightforward to verify. The homogeneous nature of the route and component files reduces per-file review complexity, though the breadth of the addition and OpenTelemetry integration require careful attention to correctness and consistency across the example.

Possibly related PRs

Suggested labels

documentation

Suggested reviewers

  • schiller-manuel
  • birkskyum

Poem

🐰 A router takes shape with OpenTelemetry's gleam,
Routes nested like warrens in a developer's dream,
Jaeger collects traces—the paths that we trace,
From Posts, Users, Deferred—each landing its place,
Start-OTEL hops forward, observability's grace! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "Setup otel/tracing example" is directly and clearly related to the main change in the changeset. The pull request adds a comprehensive new example directory (examples/react/start-otel/) that establishes an OpenTelemetry tracing example with manual instrumentation, including Docker Compose configuration for Jaeger, OpenTelemetry SDK initialization, tracer utilities, and a complete React/TanStack Router application with tracing. The title is specific and descriptive, using meaningful terminology rather than vague language, and it accurately captures the primary objective stated in the PR description.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

🧹 Nitpick comments (18)
examples/react/start-otel/src/otel.ts (2)

8-12: Consider BatchSpanProcessor for production-like examples.

SimpleSpanProcessor exports spans synchronously, blocking the application thread. While acceptable for this initial example, consider documenting this limitation or using BatchSpanProcessor to demonstrate production-ready patterns.

If you'd like to show a more production-ready approach, apply this diff:

-import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node'
+import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-node'

 const sdk = new NodeSDK({
   serviceName: 'tanstack-start',
   spanProcessors: [
-    new SimpleSpanProcessor(
+    new BatchSpanProcessor(
       new OTLPTraceExporter({
         url: 'http://localhost:4318/v1/traces',
       }),
     ),
   ],
 })

16-16: Add error handling and graceful shutdown.

The SDK starts without error handling, which could hide initialization failures. Additionally, there's no graceful shutdown handling to ensure spans are flushed before the process exits.

Consider adding error handling and shutdown hooks:

-sdk.start()
+sdk.start().catch((error) => {
+  console.error('Error initializing OpenTelemetry SDK:', error)
+})
+
+// Gracefully shut down the SDK on process exit
+process.on('SIGTERM', () => {
+  sdk.shutdown()
+    .then(() => console.log('OpenTelemetry SDK shut down successfully'))
+    .catch((error) => console.error('Error shutting down OpenTelemetry SDK:', error))
+    .finally(() => process.exit(0))
+})
examples/react/start-otel/tailwind.config.mjs (1)

1-4: Config is fine; minor optional tweaks.

Consider adding darkMode: 'class' and including MDX if you add MDX content later.

 export default {
-  content: ['./src/**/*.{js,jsx,ts,tsx}'],
+  content: ['./src/**/*.{js,jsx,ts,tsx,md,mdx}'],
+  darkMode: 'class',
 }
examples/react/start-otel/src/server.ts (1)

7-25: Use semantic-conventions, set span status, and avoid duplicate URL parsing.

This improves portability across backends and adds error status. Also compute URL once.

 export default {
   async fetch(request: Request) {
-    return tracer.startActiveSpan(
-      `${request.method} ${new URL(request.url).pathname}`,
-      async (span) => {
+    const url = new URL(request.url)
+    return tracer.startActiveSpan(
+      `${request.method} ${url.pathname}`,
+      async (span) => {
         try {
-          span.setAttribute('http.method', request.method)
-          span.setAttribute('http.url', request.url)
-          span.setAttribute('http.route', new URL(request.url).pathname)
+          // Prefer semantic-conventions constants if available
+          // (requires adding @opentelemetry/semantic-conventions)
+          span.setAttribute('http.method', request.method)
+          span.setAttribute('http.url', request.url)
+          span.setAttribute('http.route', url.pathname)
           const response = await handler.fetch(request)
-          span.setAttribute('http.status_code', response.status)
+          span.setAttribute('http.status_code', response.status)
           return response
-        } catch (error: any) {
-          span.recordException(error)
+        } catch (error: unknown) {
+          span.recordException(error as Error)
+          // Mark span as error for backends that rely on status
+          // import { SpanStatusCode } from '@opentelemetry/api'
+          // span.setStatus({ code: SpanStatusCode.ERROR })
           throw error
         } finally {
           span.end()
         }
       },
     )
   },
 }

If you add semantic constants, replace the string keys with constants (e.g., HTTP_REQUEST_METHOD, URL_FULL, HTTP_RESPONSE_STATUS_CODE). As per coding guidelines.

examples/react/start-otel/tsconfig.json (1)

3-21: Great strict base; consider a few extra safety knobs.

Optional additions that catch more issues in examples without extra noise.

   "compilerOptions": {
     "strict": true,
+    "noUncheckedIndexedAccess": true,
+    "exactOptionalPropertyTypes": true,
+    "noImplicitOverride": true,
+    "verbatimModuleSyntax": true,
     "esModuleInterop": true,
@@
-    "allowJs": true,
+    "allowJs": false,

Based on learnings.

examples/react/start-otel/src/components/UserError.tsx (1)

1-6: Consider consolidating error components.

UserErrorComponent and PostErrorComponent (in PostError.tsx) are identical except for naming. For an example demonstrating patterns, having separate components shows flexibility, but you could also consolidate to a single reusable error component if preferred.

examples/react/start-otel/src/router.tsx (2)

11-12: Pass the component directly (no wrapper needed).

defaultNotFoundComponent accepts a component. Passing NotFound directly keeps it simple.

-    defaultNotFoundComponent: () => <NotFound />,
+    defaultNotFoundComponent: NotFound,

1-4: Import alias consistency.

Elsewhere in this example you use the "~" alias for src. Consider aligning for consistency.

-import { DefaultCatchBoundary } from './components/DefaultCatchBoundary'
-import { NotFound } from './components/NotFound'
+import { DefaultCatchBoundary } from '~/components/DefaultCatchBoundary'
+import { NotFound } from '~/components/NotFound'
examples/react/start-otel/src/routes/posts_.$postId.deep.tsx (1)

1-3: Add a notFoundComponent for consistent UX with /posts/$postId.

fetchPost throws notFound() on 404. Define a local notFoundComponent so this deep route shows a friendly message like its sibling.

-import { Link, createFileRoute } from '@tanstack/react-router'
+import { Link, createFileRoute } from '@tanstack/react-router'
+import { NotFound } from '~/components/NotFound'

 export const Route = createFileRoute('/posts_/$postId/deep')({
   loader: async ({ params: { postId } }) =>
     fetchPost({
       data: postId,
     }),
   errorComponent: PostErrorComponent,
-  component: PostDeepComponent,
+  component: PostDeepComponent,
+  notFoundComponent: () => <NotFound>Post not found</NotFound>,
 })

Also applies to: 5-12

examples/react/start-otel/src/routes/__root.tsx (1)

65-69: Add a lang attribute to .

Improves a11y and i18n defaults.

-    <html>
+    <html lang="en">
examples/react/start-otel/src/components/DefaultCatchBoundary.tsx (3)

17-17: Guard error logs for production.

Avoid leaking stack/errors in prod builds; gate under a dev check.

-  console.error('DefaultCatchBoundary Error:', error)
+  if (import.meta.env.DEV) {
+    console.error('DefaultCatchBoundary Error:', error)
+  }

20-21: Improve error announcement for a11y.

Expose the error to assistive tech.

-  return (
-    <div className="min-w-0 flex-1 p-4 flex flex-col items-center justify-center gap-6">
+  return (
+    <div
+      className="min-w-0 flex-1 p-4 flex flex-col items-center justify-center gap-6"
+      role="alert"
+      aria-live="assertive"
+    >

23-27: Set explicit button type.

Prevents accidental form submission inside forms.

-        <button
+        <button
+          type="button"
           onClick={() => {
             router.invalidate()
           }}
examples/react/start-otel/src/utils/posts.tsx (3)

44-51: Set OTEL error status and useful attrs; prefer strict typing for error.

Record count on success and set ERROR status on failures; avoid any.

-    span.setStatus({ code: SpanStatusCode.OK })
-      return (posts as Array<PostType>).slice(0, 10)
-    } catch (error: any) {
-      span.recordException(error)
+    span.setAttribute('posts.count', (posts as Array<PostType>).length)
+    span.setStatus({ code: SpanStatusCode.OK })
+    return (posts as Array<PostType>).slice(0, 10)
+    } catch (error: unknown) {
+      span.recordException(error as any)
+      span.setStatus({
+        code: SpanStatusCode.ERROR,
+        message: error instanceof Error ? error.message : String(error),
+      })
       throw error
     } finally {
       span.end()
     }

1-1: Nit: use .ts (no JSX).

The file contains no JSX; rename to posts.ts to reduce unnecessary TSX parsing.


17-25: Consider fetch timeouts.

Network calls can hang; add AbortController with a short timeout (e.g., 5s) around fetch to improve resilience.

Also applies to: 37-41

examples/react/start-otel/src/routes/api/users.ts (2)

57-59: Add basic caching for list endpoint.

Reduce upstream load and improve perf.

-        return json(
-          list.map((u) => ({ id: u.id, name: u.name, email: u.email })),
-        )
+        return json(
+          list.map((u) => ({ id: u.id, name: u.name, email: u.email })),
+          { headers: { 'cache-control': 'public, max-age=60' } },
+        )

45-51: Optional: add a fetch timeout and trace child span.

Use AbortController and create a child span (e.g., tracer.startActiveSpan('GET /api/users')) for consistency with server tracing.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 521e737 and 4780458.

⛔ Files ignored due to path filters (8)
  • examples/react/start-otel/public/android-chrome-192x192.png is excluded by !**/*.png
  • examples/react/start-otel/public/android-chrome-512x512.png is excluded by !**/*.png
  • examples/react/start-otel/public/apple-touch-icon.png is excluded by !**/*.png
  • examples/react/start-otel/public/favicon-16x16.png is excluded by !**/*.png
  • examples/react/start-otel/public/favicon-32x32.png is excluded by !**/*.png
  • examples/react/start-otel/public/favicon.ico is excluded by !**/*.ico
  • examples/react/start-otel/public/favicon.png is excluded by !**/*.png
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (43)
  • examples/react/start-otel/.gitignore (1 hunks)
  • examples/react/start-otel/.prettierignore (1 hunks)
  • examples/react/start-otel/.vscode/settings.json (1 hunks)
  • examples/react/start-otel/README.md (1 hunks)
  • examples/react/start-otel/docker-compose.yml (1 hunks)
  • examples/react/start-otel/package.json (1 hunks)
  • examples/react/start-otel/postcss.config.mjs (1 hunks)
  • examples/react/start-otel/public/site.webmanifest (1 hunks)
  • examples/react/start-otel/src/components/DefaultCatchBoundary.tsx (1 hunks)
  • examples/react/start-otel/src/components/NotFound.tsx (1 hunks)
  • examples/react/start-otel/src/components/PostError.tsx (1 hunks)
  • examples/react/start-otel/src/components/UserError.tsx (1 hunks)
  • examples/react/start-otel/src/otel.ts (1 hunks)
  • examples/react/start-otel/src/routeTree.gen.ts (1 hunks)
  • examples/react/start-otel/src/router.tsx (1 hunks)
  • examples/react/start-otel/src/routes/__root.tsx (1 hunks)
  • examples/react/start-otel/src/routes/_pathlessLayout.tsx (1 hunks)
  • examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout.tsx (1 hunks)
  • examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout/route-a.tsx (1 hunks)
  • examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout/route-b.tsx (1 hunks)
  • examples/react/start-otel/src/routes/api/users.$userId.ts (1 hunks)
  • examples/react/start-otel/src/routes/api/users.ts (1 hunks)
  • examples/react/start-otel/src/routes/customScript[.]js.ts (1 hunks)
  • examples/react/start-otel/src/routes/deferred.tsx (1 hunks)
  • examples/react/start-otel/src/routes/index.tsx (1 hunks)
  • examples/react/start-otel/src/routes/posts.$postId.tsx (1 hunks)
  • examples/react/start-otel/src/routes/posts.index.tsx (1 hunks)
  • examples/react/start-otel/src/routes/posts.tsx (1 hunks)
  • examples/react/start-otel/src/routes/posts_.$postId.deep.tsx (1 hunks)
  • examples/react/start-otel/src/routes/redirect.tsx (1 hunks)
  • examples/react/start-otel/src/routes/users.$userId.tsx (1 hunks)
  • examples/react/start-otel/src/routes/users.index.tsx (1 hunks)
  • examples/react/start-otel/src/routes/users.tsx (1 hunks)
  • examples/react/start-otel/src/server.ts (1 hunks)
  • examples/react/start-otel/src/styles/app.css (1 hunks)
  • examples/react/start-otel/src/utils/loggingMiddleware.tsx (1 hunks)
  • examples/react/start-otel/src/utils/posts.tsx (1 hunks)
  • examples/react/start-otel/src/utils/seo.ts (1 hunks)
  • examples/react/start-otel/src/utils/tracer.ts (1 hunks)
  • examples/react/start-otel/src/utils/users.tsx (1 hunks)
  • examples/react/start-otel/tailwind.config.mjs (1 hunks)
  • examples/react/start-otel/tsconfig.json (1 hunks)
  • examples/react/start-otel/vite.config.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • examples/react/start-otel/src/utils/tracer.ts
  • examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout/route-b.tsx
  • examples/react/start-otel/src/routes/api/users.$userId.ts
  • examples/react/start-otel/src/routes/posts.tsx
  • examples/react/start-otel/src/components/UserError.tsx
  • examples/react/start-otel/src/routes/posts.index.tsx
  • examples/react/start-otel/src/routes/redirect.tsx
  • examples/react/start-otel/vite.config.ts
  • examples/react/start-otel/src/routes/users.tsx
  • examples/react/start-otel/src/router.tsx
  • examples/react/start-otel/src/utils/posts.tsx
  • examples/react/start-otel/src/utils/loggingMiddleware.tsx
  • examples/react/start-otel/src/routes/posts.$postId.tsx
  • examples/react/start-otel/src/components/NotFound.tsx
  • examples/react/start-otel/src/routes/_pathlessLayout.tsx
  • examples/react/start-otel/src/routes/__root.tsx
  • examples/react/start-otel/src/utils/users.tsx
  • examples/react/start-otel/src/server.ts
  • examples/react/start-otel/src/routes/deferred.tsx
  • examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout/route-a.tsx
  • examples/react/start-otel/src/components/PostError.tsx
  • examples/react/start-otel/src/routes/customScript[.]js.ts
  • examples/react/start-otel/src/routes/posts_.$postId.deep.tsx
  • examples/react/start-otel/src/routeTree.gen.ts
  • examples/react/start-otel/src/routes/users.$userId.tsx
  • examples/react/start-otel/src/routes/users.index.tsx
  • examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout.tsx
  • examples/react/start-otel/src/components/DefaultCatchBoundary.tsx
  • examples/react/start-otel/src/otel.ts
  • examples/react/start-otel/src/routes/api/users.ts
  • examples/react/start-otel/src/routes/index.tsx
  • examples/react/start-otel/src/utils/seo.ts
examples/{react,solid}/**

📄 CodeRabbit inference engine (AGENTS.md)

Keep example applications under examples/react/ and examples/solid/

Files:

  • examples/react/start-otel/src/utils/tracer.ts
  • examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout/route-b.tsx
  • examples/react/start-otel/src/routes/api/users.$userId.ts
  • examples/react/start-otel/README.md
  • examples/react/start-otel/tsconfig.json
  • examples/react/start-otel/src/routes/posts.tsx
  • examples/react/start-otel/postcss.config.mjs
  • examples/react/start-otel/src/components/UserError.tsx
  • examples/react/start-otel/src/routes/posts.index.tsx
  • examples/react/start-otel/src/routes/redirect.tsx
  • examples/react/start-otel/vite.config.ts
  • examples/react/start-otel/tailwind.config.mjs
  • examples/react/start-otel/src/routes/users.tsx
  • examples/react/start-otel/src/router.tsx
  • examples/react/start-otel/src/utils/posts.tsx
  • examples/react/start-otel/src/utils/loggingMiddleware.tsx
  • examples/react/start-otel/src/routes/posts.$postId.tsx
  • examples/react/start-otel/src/components/NotFound.tsx
  • examples/react/start-otel/src/routes/_pathlessLayout.tsx
  • examples/react/start-otel/src/routes/__root.tsx
  • examples/react/start-otel/public/site.webmanifest
  • examples/react/start-otel/src/utils/users.tsx
  • examples/react/start-otel/src/server.ts
  • examples/react/start-otel/src/routes/deferred.tsx
  • examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout/route-a.tsx
  • examples/react/start-otel/src/components/PostError.tsx
  • examples/react/start-otel/src/routes/customScript[.]js.ts
  • examples/react/start-otel/src/routes/posts_.$postId.deep.tsx
  • examples/react/start-otel/src/routeTree.gen.ts
  • examples/react/start-otel/package.json
  • examples/react/start-otel/src/routes/users.$userId.tsx
  • examples/react/start-otel/src/routes/users.index.tsx
  • examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout.tsx
  • examples/react/start-otel/src/components/DefaultCatchBoundary.tsx
  • examples/react/start-otel/src/otel.ts
  • examples/react/start-otel/src/routes/api/users.ts
  • examples/react/start-otel/src/styles/app.css
  • examples/react/start-otel/docker-compose.yml
  • examples/react/start-otel/src/routes/index.tsx
  • examples/react/start-otel/src/utils/seo.ts
**/src/routes/**

📄 CodeRabbit inference engine (AGENTS.md)

Place file-based routes under src/routes/ directories

Files:

  • examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout/route-b.tsx
  • examples/react/start-otel/src/routes/api/users.$userId.ts
  • examples/react/start-otel/src/routes/posts.tsx
  • examples/react/start-otel/src/routes/posts.index.tsx
  • examples/react/start-otel/src/routes/redirect.tsx
  • examples/react/start-otel/src/routes/users.tsx
  • examples/react/start-otel/src/routes/posts.$postId.tsx
  • examples/react/start-otel/src/routes/_pathlessLayout.tsx
  • examples/react/start-otel/src/routes/__root.tsx
  • examples/react/start-otel/src/routes/deferred.tsx
  • examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout/route-a.tsx
  • examples/react/start-otel/src/routes/customScript[.]js.ts
  • examples/react/start-otel/src/routes/posts_.$postId.deep.tsx
  • examples/react/start-otel/src/routes/users.$userId.tsx
  • examples/react/start-otel/src/routes/users.index.tsx
  • examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout.tsx
  • examples/react/start-otel/src/routes/api/users.ts
  • examples/react/start-otel/src/routes/index.tsx
**/package.json

📄 CodeRabbit inference engine (AGENTS.md)

Use workspace:* protocol for internal dependencies in package.json files

Files:

  • examples/react/start-otel/package.json
🧠 Learnings (2)
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
PR: TanStack/router#0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to **/*.{ts,tsx} : Use TypeScript in strict mode with extensive type safety across the codebase

Applied to files:

  • examples/react/start-otel/tsconfig.json
📚 Learning: 2025-10-01T18:31:35.420Z
Learnt from: schiller-manuel
PR: TanStack/router#5330
File: e2e/react-start/custom-basepath/src/routeTree.gen.ts:58-61
Timestamp: 2025-10-01T18:31:35.420Z
Learning: Do not review files named `routeTree.gen.ts` in TanStack Router repositories, as these are autogenerated files that should not be manually modified.

Applied to files:

  • examples/react/start-otel/.vscode/settings.json
  • examples/react/start-otel/src/routeTree.gen.ts
🧬 Code graph analysis (25)
examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout/route-b.tsx (3)
examples/react/start-otel/src/routes/_pathlessLayout.tsx (1)
  • Route (3-5)
examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout.tsx (1)
  • Route (3-5)
examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout/route-a.tsx (1)
  • Route (3-7)
examples/react/start-otel/src/routes/api/users.$userId.ts (4)
examples/react/start-otel/src/routes/api/users.ts (1)
  • Route (41-63)
examples/react/start-otel/src/routes/users.$userId.tsx (1)
  • Route (6-26)
examples/react/start-otel/src/server.ts (1)
  • fetch (7-26)
examples/react/start-otel/src/utils/users.tsx (1)
  • User (1-5)
examples/react/start-otel/src/routes/posts.tsx (2)
examples/react/start-otel/src/routes/posts.$postId.tsx (1)
  • Route (6-13)
examples/react/start-otel/src/utils/posts.tsx (1)
  • fetchPosts (33-53)
examples/react/start-otel/src/routes/posts.index.tsx (4)
examples/react/start-otel/src/routes/index.tsx (1)
  • Route (3-5)
examples/react/start-otel/src/routes/posts.$postId.tsx (1)
  • Route (6-13)
examples/react/start-otel/src/routes/posts.tsx (1)
  • Route (4-7)
examples/react/start-otel/src/routes/users.index.tsx (1)
  • Route (3-5)
examples/react/start-otel/src/routes/redirect.tsx (2)
examples/react/start-otel/src/routes/posts.index.tsx (1)
  • Route (3-5)
examples/react/start-otel/src/routes/posts.tsx (1)
  • Route (4-7)
examples/react/start-otel/src/routes/users.tsx (3)
examples/react/start-otel/src/routes/api/users.ts (1)
  • Route (41-63)
examples/react/start-otel/src/routes/users.$userId.tsx (1)
  • Route (6-26)
examples/react/start-otel/src/utils/users.tsx (1)
  • User (1-5)
examples/react/start-otel/src/router.tsx (2)
examples/react/start-otel/src/components/DefaultCatchBoundary.tsx (1)
  • DefaultCatchBoundary (10-53)
examples/react/start-otel/src/components/NotFound.tsx (1)
  • NotFound (3-25)
examples/react/start-otel/src/utils/posts.tsx (2)
examples/react/start-otel/src/server.ts (1)
  • fetch (7-26)
examples/react/start-otel/src/utils/tracer.ts (1)
  • tracer (3-3)
examples/react/start-otel/src/routes/posts.$postId.tsx (4)
examples/react/start-otel/src/routes/posts_.$postId.deep.tsx (1)
  • Route (5-12)
examples/react/start-otel/src/utils/posts.tsx (1)
  • fetchPost (12-31)
examples/react/start-otel/src/components/PostError.tsx (1)
  • PostErrorComponent (4-6)
examples/react/start-otel/src/components/NotFound.tsx (1)
  • NotFound (3-25)
examples/react/start-otel/src/components/NotFound.tsx (4)
e2e/react-start/basic-cloudflare/src/components/NotFound.tsx (1)
  • NotFound (3-25)
e2e/react-start/server-routes/src/components/NotFound.tsx (1)
  • NotFound (3-25)
examples/react/start-basic-cloudflare/src/components/NotFound.tsx (1)
  • NotFound (3-25)
e2e/solid-start/server-routes/src/components/NotFound.tsx (1)
  • NotFound (3-25)
examples/react/start-otel/src/routes/_pathlessLayout.tsx (3)
examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout.tsx (1)
  • Route (3-5)
examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout/route-a.tsx (1)
  • Route (3-7)
examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout/route-b.tsx (1)
  • Route (3-7)
examples/react/start-otel/src/routes/__root.tsx (4)
examples/react/start-otel/src/routes/customScript[.]js.ts (1)
  • Route (3-15)
examples/react/start-otel/src/utils/seo.ts (1)
  • seo (1-33)
examples/react/start-otel/src/components/DefaultCatchBoundary.tsx (1)
  • DefaultCatchBoundary (10-53)
examples/react/start-otel/src/components/NotFound.tsx (1)
  • NotFound (3-25)
examples/react/start-otel/src/server.ts (1)
examples/react/start-otel/src/utils/tracer.ts (1)
  • tracer (3-3)
examples/react/start-otel/src/routes/deferred.tsx (1)
examples/solid/start-basic/src/routes/deferred.tsx (2)
  • Deferred (31-62)
  • deferredStuff (19-27)
examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout/route-a.tsx (3)
examples/react/start-otel/src/routes/_pathlessLayout.tsx (1)
  • Route (3-5)
examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout.tsx (1)
  • Route (3-5)
examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout/route-b.tsx (1)
  • Route (3-7)
examples/react/start-otel/src/components/PostError.tsx (1)
examples/react/start-basic/src/components/PostError.tsx (1)
  • PostErrorComponent (4-6)
examples/react/start-otel/src/routes/customScript[.]js.ts (1)
examples/react/start-otel/src/routes/__root.tsx (1)
  • Route (15-63)
examples/react/start-otel/src/routes/posts_.$postId.deep.tsx (3)
examples/react/start-otel/src/routes/posts.$postId.tsx (1)
  • Route (6-13)
examples/react/start-otel/src/utils/posts.tsx (1)
  • fetchPost (12-31)
examples/react/start-otel/src/components/PostError.tsx (1)
  • PostErrorComponent (4-6)
examples/react/start-otel/src/routeTree.gen.ts (2)
e2e/react-router/js-only-file-based/src/routeTree.gen.js (12)
  • PathlessLayoutRoute (21-24)
  • IndexRoute (30-34)
  • PostsIndexRoute (35-39)
  • PostsPostIdRoute (40-44)
  • PathlessLayoutNestedLayoutRoute (45-49)
  • PathlessLayoutNestedLayoutRouteBRoute (50-55)
  • PathlessLayoutNestedLayoutRouteARoute (56-61)
  • PathlessLayoutRouteWithChildren (86-88)
  • PathlessLayoutNestedLayoutRouteWithChildren (77-80)
  • PathlessLayoutNestedLayoutRouteChildren (72-75)
  • PathlessLayoutRouteChildren (82-84)
  • rootRouteChildren (90-94)
examples/react/start-otel/src/router.tsx (1)
  • getRouter (6-15)
examples/react/start-otel/src/routes/users.$userId.tsx (4)
examples/react/start-otel/src/routes/api/users.$userId.ts (1)
  • Route (5-32)
examples/react/start-otel/src/utils/users.tsx (1)
  • User (1-5)
examples/react/start-otel/src/components/UserError.tsx (1)
  • UserErrorComponent (4-6)
examples/react/start-otel/src/components/NotFound.tsx (1)
  • NotFound (3-25)
examples/react/start-otel/src/routes/users.index.tsx (2)
examples/react/start-otel/src/routes/api/users.ts (1)
  • Route (41-63)
examples/react/start-otel/src/routes/users.$userId.tsx (1)
  • Route (6-26)
examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout.tsx (3)
examples/react/start-otel/src/routes/_pathlessLayout.tsx (1)
  • Route (3-5)
examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout/route-a.tsx (1)
  • Route (3-7)
examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout/route-b.tsx (1)
  • Route (3-7)
examples/react/start-otel/src/components/DefaultCatchBoundary.tsx (3)
e2e/react-start/server-routes/src/components/DefaultCatchBoundary.tsx (1)
  • DefaultCatchBoundary (10-53)
examples/react/start-basic-cloudflare/src/components/DefaultCatchBoundary.tsx (1)
  • DefaultCatchBoundary (10-53)
packages/react-router/src/CatchBoundary.tsx (1)
  • CatchBoundaryImpl (31-78)
examples/react/start-otel/src/routes/api/users.ts (4)
packages/start-server-core/src/request-response.ts (1)
  • getRequestHeaders (77-80)
examples/react/start-otel/src/routes/api/users.$userId.ts (1)
  • Route (5-32)
examples/react/start-otel/src/server.ts (1)
  • fetch (7-26)
examples/react/start-otel/src/utils/users.tsx (1)
  • User (1-5)
examples/react/start-otel/src/routes/index.tsx (1)
examples/react/start-otel/src/routes/__root.tsx (1)
  • Route (15-63)
🪛 Biome (2.1.2)
examples/react/start-otel/src/routes/deferred.tsx

[error] 43-43: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 53-53: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

🪛 LanguageTool
examples/react/start-otel/README.md

[uncategorized] ~25-~25: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...TanStack Router app. In production, the markdown doc pages are fetched from the GitHub r...

(MARKDOWN_NNP)


[style] ~71-~71: Using many exclamation marks might seem excessive (in this case: 8 exclamation marks for a text that’s 1725 characters long)
Context: ...e manually reloaded in the browser. > [!WARNING] > You will need to update the docs/config.json file (in the project's repo) if you add a new doc page!

(EN_EXCESSIVE_EXCLAMATION)

🪛 markdownlint-cli2 (0.18.1)
examples/react/start-otel/README.md

46-46: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


53-53: Blank line inside blockquote

(MD028, no-blanks-blockquote)


66-66: Bare URL used

(MD034, no-bare-urls)


70-70: Blank line inside blockquote

(MD028, no-blanks-blockquote)

🔇 Additional comments (29)
examples/react/start-otel/.gitignore (1)

20-20: Clarify the purpose of .tanstack entry.

The .tanstack entry is vague. Is this a cache directory or build artifact that should be ignored, or is this a leftover entry that should be removed?

examples/react/start-otel/vite.config.ts (1)

10-18: No issues found — configuration is correct per official TanStack Start documentation.

TanStack Start requires you to install and add a React Vite plugin (e.g. @vitejs/plugin-react) to vite.config.ts, with viteReact() placed after tanstackStart() in the plugins array. The current configuration follows this pattern correctly and requires no changes.

examples/react/start-otel/.vscode/settings.json (1)

1-11: LGTM!

The VSCode configuration correctly excludes the autogenerated routeTree.gen.ts from file watching, search indexing, and marks it readonly to prevent manual edits. This aligns with TanStack Router best practices.

Based on learnings

examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout/route-b.tsx (1)

1-11: LGTM!

The route component follows TanStack Router conventions and matches the pattern established by sibling routes in the example.

examples/react/start-otel/.prettierignore (1)

1-4: LGTM!

The Prettier ignore patterns appropriately exclude generated files, build artifacts, and lock files from formatting.

examples/react/start-otel/postcss.config.mjs (1)

1-6: LGTM!

Standard PostCSS configuration with Tailwind CSS and Autoprefixer using default plugin settings.

examples/react/start-otel/docker-compose.yml (2)

1-12: Docker Compose configuration is appropriate for the example.

The Jaeger setup correctly exposes OTLP ports and enables the OTLP collector, which aligns with the OpenTelemetry configuration in src/otel.ts that targets port 4318.


4-4: Upgrade Jaeger image to latest stable version; verify security impact first.

The latest stable Jaeger is 2.11.0 (v2 series), while version 1.57 is from the older v1 branch. CVE-2024-24787, a Go/agent build issue, was fixed in agent versions 1.57.0, so 1.57 itself should have this patch. However, CVE-2023-36656 (XSS in Jaeger UI) is fixed in jaeger-ui ≥ v1.31.0, and images bundling older UI may be affected. Before upgrading, manually verify whether the all-in-one:1.57 image contains a vulnerable UI version, and review the changelog between 1.57 and 2.11.0 for breaking changes.

examples/react/start-otel/src/utils/tracer.ts (1)

1-3: LGTM!

The tracer utility correctly uses the OpenTelemetry API to obtain a named tracer instance, following OpenTelemetry best practices.

examples/react/start-otel/src/routes/posts.index.tsx (1)

3-9: LGTM for the index route.

Path and component wiring look correct and consistent with other index routes.

examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout/route-a.tsx (1)

3-11: LGTM for pathless nested route.

Matches the pattern used by sibling routes; component is scoped and simple.

examples/react/start-otel/src/routes/api/users.$userId.ts (1)

8-29: LGTM with minor observations.

The handler correctly fetches and validates user data, with appropriate error handling. The implementation is suitable for an example/demo application.

Note: The broad catch block returns 404 for all errors. In a production application, you might want to distinguish between actual "not found" responses (404) and other failures (500), but for a demonstration example this simplification is acceptable.

examples/react/start-otel/src/utils/loggingMiddleware.tsx (1)

3-41: LGTM!

The middleware correctly measures client-to-server round-trip timing by capturing timestamps at each boundary and computing durations. The composition pattern using preLogMiddleware ensures proper context flow between client and server.

examples/react/start-otel/src/routes/deferred.tsx (1)

40-55: LGTM!

The deferred loading pattern correctly uses Suspense with Await to handle progressive rendering of async data. The static analysis warnings about the children prop can be safely ignored—the Await component from TanStack Router intentionally accepts a render function via the children prop, matching the established API pattern.

examples/react/start-otel/src/utils/users.tsx (1)

1-5: LGTM!

Clean and straightforward type definition for the User entity used throughout the example.

examples/react/start-otel/src/routes/index.tsx (1)

3-13: LGTM!

Simple and appropriate home route for the example application.

examples/react/start-otel/src/routes/_pathlessLayout.tsx (1)

3-16: LGTM!

Correctly implements a pathless layout route with proper Outlet placement for nested routes. The implementation aligns with the nested pathless route structure shown in related files.

examples/react/start-otel/src/routes/redirect.tsx (1)

1-9: LGTM!

The redirect route is correctly implemented using TanStack Router's redirect pattern in beforeLoad.

examples/react/start-otel/src/routes/posts.tsx (2)

4-7: LGTM!

Route configuration is correct with proper loader and component assignment.


9-38: LGTM!

The component correctly renders the post list with navigation links. The addition of the non-existent post on line 15 is intentional for demonstrating error handling behavior in this example.

examples/react/start-otel/src/routes/users.index.tsx (1)

1-19: LGTM!

Simple and clean index route implementation with proper navigation link.

examples/react/start-otel/src/components/NotFound.tsx (1)

1-25: LGTM!

NotFound component follows the established pattern used across other examples in the codebase. Implementation is clean and correct.

examples/react/start-otel/src/components/PostError.tsx (1)

1-6: LGTM!

PostErrorComponent correctly implements the error handling pattern consistent with other examples in the codebase.

examples/react/start-otel/src/routes/customScript[.]js.ts (1)

1-15: LGTM!

The custom script route correctly demonstrates serving JavaScript dynamically with proper Content-Type headers. The script is properly referenced in the root route configuration.

examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout.tsx (1)

1-34: LGTM!

The nested layout correctly implements TanStack Router's pathless layout pattern with proper navigation and nested route rendering via Outlet.

examples/react/start-otel/src/routes/users.tsx (1)

25-28: Ensure the detail route surfaces NotFound (not generic error).

This dummy entry is great for demoing 404s. Make sure /users/$userId throws notFound() on a 404 so the route’s notFoundComponent renders; otherwise this link will hit the error boundary. See suggested fix in users.$userId.tsx.

examples/react/start-otel/src/styles/app.css (1)

19-21: A11y toggle code is missing—the .using-mouse class is never applied.

The CSS rule at lines 19–21 has no effect because no JavaScript in the codebase applies the .using-mouse class to the DOM. There are no event listeners for mouse/keyboard detection in examples/react/start-otel/src/. The customScript.js endpoint only outputs a placeholder log, not a toggle implementation.

Either remove this orphaned CSS rule, or implement the missing JavaScript toggle that detects mouse vs. keyboard input and applies .using-mouse accordingly.

examples/react/start-otel/src/routes/posts.$postId.tsx (1)

6-13: Route wiring and loader look solid.

Loader delegates to server fn, dedicated notFound and error components are set. Good separation of concerns.

examples/react/start-otel/src/routeTree.gen.ts (1)

1-10: Autogenerated file — no manual review.

routeTree.gen.ts is generated and should not be edited.

Based on learnings

Comment on lines +14 to +15
/public/build# Sentry Config File
.env.sentry-build-plugin
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix comment placement and formatting.

The Sentry Config File comment should be on its own line before .env.sentry-build-plugin, not appended to the end of /public/build. Additionally, .gitignore files should end with a newline.

-/public/build# Sentry Config File
+/public/build
+# Sentry Config File
 .env.sentry-build-plugin

Ensure the file ends with a newline after the last entry.

🤖 Prompt for AI Agents
In examples/react/start-otel/.gitignore around lines 14 to 15, the inline
comment "Sentry Config File" is appended to the `/public/build` entry and the
file is missing a trailing newline; move the comment to its own line immediately
above `.env.sentry-build-plugin` (e.g. a standalone line containing "Sentry
Config File") so it does not annotate `/public/build`, and ensure the file ends
with a single newline character after the last entry.

Comment on lines +6 to +10
"scripts": {
"dev": "vite dev",
"build": "vite build && tsc --noEmit",
"start": "node .output/server/index.mjs"
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify the start script output path.

Vite usually emits to dist/ by default; the script starts .output/server/index.mjs. Ensure your build config writes to .output/server.


🏁 Script executed:

#!/bin/bash
set -euo pipefail
# Check for vite config and SSR/output settings
fd -HI '^vite\.config\.(ts|mjs|js)$' .
rg -n --no-messages -C2 'outDir|ssr|build' $(fd -HI '^vite\.config\.(ts|mjs|js)$' . || echo)
# Confirm referenced file exists (if already built)
test -f examples/react/start-otel/.output/server/index.mjs && echo "Found .output/server/index.mjs" || echo "Note: .output/server/index.mjs not present (build not run or outDir differs)."

Length of output: 33906


#!/bin/bash
# Extract vite config for start-otel specifically
cat examples/react/start-otel/vite.config.ts


---

🏁 Script executed:

```shell
#!/bin/bash
cat examples/react/start-otel/vite.config.ts

Length of output: 416



---

🏁 Script executed:

```shell
#!/bin/bash
# Check the package.json for start-otel to confirm the start script
cat examples/react/start-otel/package.json

echo "---"

# Check a few other start examples to see the pattern
cat examples/react/start-basic/package.json 2>/dev/null | grep -A5 '"scripts"'

Length of output: 1180



---

🌐 Web query:

```web
TanStack Start tanstackStart vite plugin outDir .output configuration

💡 Result:

Short answer: TanStack Start's Vite plugin no longer always produces a .output folder by itself — to get the traditional .output server bundle you must enable Nitro in your Vite build (either Nitro v3's vite plugin or the compatibility @tanstack/nitro-v2-vite-plugin). Add the Nitro Vite plugin alongside tanstackStart and the framework plugin; Nitro will generate the .output/server entry (or a dist/ server bundle if you don't use the Nitro plugin). [1][2][3]

Example (vite.config.ts):
import { defineConfig } from 'vite'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import { nitro } from 'nitro/vite' // or use @tanstack/nitro-v2-vite-plugin
import viteReact from '@vitejs/plugin-react'

export default defineConfig({
plugins: [
tanstackStart(),
nitro({ /* nitro config / preset */ }),
viteReact(),
],
})

Notes:

  • Use @tanstack/nitro-v2-vite-plugin as a fallback for older Start RCs; Nitro v3's vite plugin is the official path. [1][2]
  • If you run build without the Nitro plugin you may get dist/ (server + client) and not .output; adding the Nitro plugin makes .output/server/index.mjs available for Node/Bun deployment. [3][2]

Sources:

  • TanStack Start hosting docs (Nitro + nitro-v2 plugin recommendation). [1][2]
  • Community writeup on missing .output when Nitro isn't used. [3]


---

🏁 Script executed:

```shell
#!/bin/bash
# Search for nitro references in start-otel vite config
echo "=== start-otel vite.config.ts ===" 
grep -i nitro examples/react/start-otel/vite.config.ts || echo "(no nitro reference)"

echo ""
echo "=== Checking start-basic vite.config.ts ===" 
cat examples/react/start-basic/vite.config.ts

echo ""
echo "=== Checking start-basic for nitro import ===" 
grep -i nitro examples/react/start-basic/vite.config.ts || echo "(no nitro reference found)"

Length of output: 590


Add Nitro plugin to vite.config.ts or update the start script path to match actual build output.

The vite.config.ts for start-otel uses tanstackStart() but lacks the Nitro plugin required to produce the .output/server/index.mjs that the start script expects. Without Nitro, Vite builds to dist/ by default, causing the start script to fail. Either add the Nitro plugin (e.g., @tanstack/nitro-v2-vite-plugin or nitro/vite) to generate .output/server, or update the start script to reference the actual build output directory.

🤖 Prompt for AI Agents
In examples/react/start-otel/package.json around lines 6 to 10, the "start"
script expects .output/server/index.mjs but the Vite config uses tanstackStart()
without a Nitro plugin so the build produces dist/ instead; either add a Nitro
Vite plugin (for example @tanstack/nitro-v2-vite-plugin or nitro/vite) to
vite.config.ts so the build emits .output/server/index.mjs, or change the
"start" script to point to the actual build output (e.g., dist/ or the correct
server entry) to match what the current build produces.

Comment on lines +11 to +23
"dependencies": {
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/exporter-trace-otlp-proto": "^0.206.0",
"@opentelemetry/sdk-node": "^0.206.0",
"@opentelemetry/sdk-trace-node": "^2.1.0",
"@tanstack/react-router": "^1.133.15",
"@tanstack/react-router-devtools": "^1.133.15",
"@tanstack/react-start": "^1.133.15",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"tailwind-merge": "^2.6.0",
"zod": "^3.24.2"
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Use workspace: for internal TanStack packages in the monorepo.*

This keeps examples pinned to local workspace builds and avoids version drift.

-    "@tanstack/react-router": "^1.133.15",
-    "@tanstack/react-router-devtools": "^1.133.15",
-    "@tanstack/react-start": "^1.133.15",
+    "@tanstack/react-router": "workspace:*",
+    "@tanstack/react-router-devtools": "workspace:*",
+    "@tanstack/react-start": "workspace:*",

As per coding guidelines.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"dependencies": {
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/exporter-trace-otlp-proto": "^0.206.0",
"@opentelemetry/sdk-node": "^0.206.0",
"@opentelemetry/sdk-trace-node": "^2.1.0",
"@tanstack/react-router": "^1.133.15",
"@tanstack/react-router-devtools": "^1.133.15",
"@tanstack/react-start": "^1.133.15",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"tailwind-merge": "^2.6.0",
"zod": "^3.24.2"
},
"dependencies": {
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/exporter-trace-otlp-proto": "^0.206.0",
"@opentelemetry/sdk-node": "^0.206.0",
"@opentelemetry/sdk-trace-node": "^2.1.0",
"@tanstack/react-router": "workspace:*",
"@tanstack/react-router-devtools": "workspace:*",
"@tanstack/react-start": "workspace:*",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"tailwind-merge": "^2.6.0",
"zod": "^3.24.2"
},
🤖 Prompt for AI Agents
In examples/react/start-otel/package.json around lines 11 to 23, the three
internal TanStack packages (@tanstack/react-router,
@tanstack/react-router-devtools, @tanstack/react-start) are pinned to external
versions; replace their version strings with "workspace:*" so the example uses
local monorepo builds, then run the workspace package manager (pnpm/npm/yarn) to
refresh lockfiles; keep other dependencies unchanged.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Align OpenTelemetry package versions (avoid mixing 0.x, 1.x, 2.x).

Mixing majors across OTel core packages can cause runtime incompatibilities. Align all @opentelemetry/* core packages to a single compatible line and avoid redundant SDKs (sdk-node vs sdk-trace-node).

Example (illustrative — pick one coherent version set used by the repo):

-    "@opentelemetry/api": "^1.9.0",
-    "@opentelemetry/exporter-trace-otlp-proto": "^0.206.0",
-    "@opentelemetry/sdk-node": "^0.206.0",
-    "@opentelemetry/sdk-trace-node": "^2.1.0",
+    "@opentelemetry/api": "^1.9.0",
+    "@opentelemetry/sdk-node": "<aligned-version>",
+    "@opentelemetry/exporter-trace-otlp-proto": "<aligned-version>",
+    // Remove if using sdk-node:
+    // "@opentelemetry/sdk-trace-node": "<aligned-version>",
+    // Optional but recommended for stable keys:
+    "@opentelemetry/semantic-conventions": "<aligned-version>",

🏁 Script executed:

#!/bin/bash
set -euo pipefail
pkg=examples/react/start-otel/package.json
echo "OTel package versions in $pkg"
jq -r '
  [.dependencies,.devDependencies]|add|to_entries
  | map(select(.key|startswith("@opentelemetry/")))
  | .[] | "\(.key) = \(.value)"
' "$pkg" | sort
echo
echo "Distinct major.minor groups:"
jq -r '
  [.dependencies,.devDependencies]|add|to_entries
  | map(select(.key|startswith("@opentelemetry/")))
  | .[] | .value
' "$pkg" | sed -E 's/[^0-9]*([0-9]+)\.([0-9]+).*/\1.\2/' | sort -u

Length of output: 261


</web_search>


🏁 Script executed:

#!/bin/bash
# Check for internal workspace dependencies in this package.json
echo "=== Internal dependencies in examples/react/start-otel/package.json ==="
jq -r '.dependencies | to_entries[] | select(.value | startswith("workspace:")) | "\(.key): \(.value)"' examples/react/start-otel/package.json 2>/dev/null || echo "No workspace dependencies found"
echo
# Find all package.json files in the repo and extract OTel versions
echo "=== OpenTelemetry versions across all package.json files ==="
find . -name "package.json" -type f | while read -r pf; do
  otel_count=$(jq -r '[.dependencies,.devDependencies]|add|to_entries|map(select(.key|startswith("@opentelemetry/")))|length' "$pf" 2>/dev/null || echo "0")
  if [ "$otel_count" -gt 0 ]; then
    echo "$pf:"
    jq -r '[.dependencies,.devDependencies]|add|to_entries|map(select(.key|startswith("@opentelemetry/")))|.[]|"\(.key) = \(.value)"' "$pf" 2>/dev/null | sort
    echo
  fi
done | head -100

Length of output: 366


🌐 Web query:

OpenTelemetry compatibility matrix versions 0.206 1.9 2.1

💡 Result:

Do you mean the OpenTelemetry package compatibilities between the "experimental" 0.* series and the "stable" 1.* / 2.* series (SDK/API/semantic-conventions packages)? If so, can you confirm which language or package (Java, JS, Python, semantic-conventions, Collector, etc.) you need the matrix for?


🌐 Web query:

JavaScript Node.js OpenTelemetry sdk-node sdk-trace-node compatibility

💡 Result:

Short answer

  • @opentelemetry/sdk-node (NodeSDK) is a wrapper/kit that composes the OpenTelemetry JS SDK pieces for Node — it commonly uses @opentelemetry/sdk-trace-node for tracing functionality. Use sdk-node + sdk-trace-node together (they’re designed to interoperate). [1][2]

Compatibility guidance

  • Match major versions: keep @opentelemetry/* packages on the same major (e.g., 2.x) to avoid API/behavior mismatches. The 2.0 SDK release introduces breaking changes, so mix-and-matching 1.x and 2.x packages is not recommended. [1]
  • Node runtime and TS requirements changed in SDK 2.x: minimum Node.js is ^18.19.0 || >=20.6.0 and TypeScript >=5.0.4; check the SDK 2.x migration guide before upgrading. [1]

Practical notes

  • If you use the Node getting-started examples, NodeSDK imports ConsoleSpanExporter (or other exporters) from @opentelemetry/sdk-trace-node and registers auto-instrumentations via @opentelemetry/auto-instrumentations-node — that’s the normal composition. [2][3]
  • For custom/manual tracing you can use @opentelemetry/sdk-trace-base directly, but sdk-trace-node provides Node-specific defaults (async_hooks context manager, resource detection, instrumentations). [1][2]

If you want I can:

  • check your package.json and recommend exact versions to align (e.g., upgrade path from 1.x → 2.x), or
  • fetch the 2.x migration guide and list the breaking-change steps.

Sources
[1] OpenTelemetry blog — Announcing the OpenTelemetry JavaScript SDK 2.0 (release notes & migration).
[2] OpenTelemetry JS docs — Node.js getting started / package list (describes @opentelemetry/sdk-node and @opentelemetry/sdk-trace-node).
[3] OpenTelemetry JS repo/docs — @opentelemetry/sdk-trace-base vs sdk-trace-node (module descriptions).


Align OpenTelemetry package versions to a single major (currently mixing 0.x, 1.x, 2.x).

Matching major versions is required to avoid API/behavior mismatches, and mix-and-matching 1.x and 2.x packages is not recommended. Your package.json currently has:

  • @opentelemetry/api: ^1.9.0 (1.x)
  • @opentelemetry/exporter-trace-otlp-proto: ^0.206.0 (0.x)
  • @opentelemetry/sdk-node: ^0.206.0 (0.x)
  • @opentelemetry/sdk-trace-node: ^2.1.0 (2.x)

@opentelemetry/sdk-node and @opentelemetry/sdk-trace-node are designed to interoperate and should be used together. Align all @opentelemetry/* packages to the same major version (recommend 2.x as the latest stable).

🤖 Prompt for AI Agents
In examples/react/start-otel/package.json around lines 11 to 23, the
OpenTelemetry dependencies use mixed major versions (0.x, 1.x, 2.x) which can
cause API/behavior mismatches; update all @opentelemetry/* packages to the same
major (recommend migrating @opentelemetry/api,
@opentelemetry/exporter-trace-otlp-proto, @opentelemetry/sdk-node, and
@opentelemetry/sdk-trace-node to matching 2.x releases), adjust their version
ranges consistently (e.g., ^2.x), run npm install to update lockfile, and run
tests/build to verify compatibility.

Comment on lines +2 to +3
"name": "",
"short_name": "",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add placeholder values for PWA manifest names.

The name and short_name fields are empty strings, which may cause PWA installation prompts to display incorrectly or fail to appear. For an example project, consider adding descriptive placeholder values.

Apply this diff to add example values:

-  "name": "",
-  "short_name": "",
+  "name": "TanStack Router OTEL Example",
+  "short_name": "OTEL Example",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"name": "",
"short_name": "",
"name": "TanStack Router OTEL Example",
"short_name": "OTEL Example",
🤖 Prompt for AI Agents
In examples/react/start-otel/public/site.webmanifest around lines 2 to 3, the
PWA manifest's "name" and "short_name" fields are empty; update them to
meaningful placeholder values so install prompts and UI show correctly (e.g.,
set "name" to a descriptive project title and "short_name" to a shorter display
label). Ensure the values are plain strings, keep short_name under ~12
characters for display, and save the manifest.

Comment on lines +1 to +72
# Welcome to TanStack.com!

This site is built with TanStack Router!

- [TanStack Router Docs](https://tanstack.com/router)

It's deployed automagically with Netlify!

- [Netlify](https://netlify.com/)

## Development

From your terminal:

```sh
pnpm install
pnpm dev
```

This starts your app in development mode, rebuilding assets on file changes.

## Editing and previewing the docs of TanStack projects locally

The documentations for all TanStack projects except for `React Charts` are hosted on [https://tanstack.com](https://tanstack.com), powered by this TanStack Router app.
In production, the markdown doc pages are fetched from the GitHub repos of the projects, but in development they are read from the local file system.

Follow these steps if you want to edit the doc pages of a project (in these steps we'll assume it's [`TanStack/form`](https://github.com/tanstack/form)) and preview them locally :

1. Create a new directory called `tanstack`.

```sh
mkdir tanstack
```

2. Enter the directory and clone this repo and the repo of the project there.

```sh
cd tanstack
git clone git@github.com:TanStack/tanstack.com.git
git clone git@github.com:TanStack/form.git
```

> [!NOTE]
> Your `tanstack` directory should look like this:
>
> ```
> tanstack/
> |
> +-- form/
> |
> +-- tanstack.com/
> ```

> [!WARNING]
> Make sure the name of the directory in your local file system matches the name of the project's repo. For example, `tanstack/form` must be cloned into `form` (this is the default) instead of `some-other-name`, because that way, the doc pages won't be found.

3. Enter the `tanstack/tanstack.com` directory, install the dependencies and run the app in dev mode:

```sh
cd tanstack.com
pnpm i
# The app will run on https://localhost:3000 by default
pnpm dev
```

4. Now you can visit http://localhost:3000/form/latest/docs/overview in the browser and see the changes you make in `tanstack/form/docs`.

> [!NOTE]
> The updated pages need to be manually reloaded in the browser.

> [!WARNING]
> You will need to update the `docs/config.json` file (in the project's repo) if you add a new doc page!
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Replace README content to match the OTEL example.

The README describes the TanStack.com documentation site workflow, including instructions for editing docs across TanStack projects. However, this is the start-otel example demonstrating OpenTelemetry integration with TanStack Router, not the tanstack.com website.

The README should describe:

  • What the OTEL example demonstrates
  • How to run the example (pnpm install, pnpm dev)
  • How to start the Jaeger instance (Docker Compose)
  • How to view traces
  • Any specific instrumentation patterns demonstrated

Apply this diff to provide appropriate documentation:

-# Welcome to TanStack.com!
+# TanStack Start + OpenTelemetry Example
 
-This site is built with TanStack Router!
+This example demonstrates OpenTelemetry tracing integration with TanStack Router and React Start.
 
-- [TanStack Router Docs](https://tanstack.com/router)
-
-It's deployed automagically with Netlify!
-
-- [Netlify](https://netlify.com/)
+## Features
+
+- Manual OpenTelemetry instrumentation
+- Jaeger for trace visualization
+- Server-side tracing with TanStack Start
 
 ## Development
 
-From your terminal:
+1. Start the Jaeger instance:
 
 ```sh
-pnpm install
-pnpm dev
+docker-compose up -d

-This starts your app in development mode, rebuilding assets on file changes.

-## Editing and previewing the docs of TanStack projects locally

-The documentations for all TanStack projects except for React Charts are hosted on https://tanstack.com, powered by this TanStack Router app.
-In production, the markdown doc pages are fetched from the GitHub repos of the projects, but in development they are read from the local file system.

-Follow these steps if you want to edit the doc pages of a project (in these steps we'll assume it's TanStack/form) and preview them locally :

-1. Create a new directory called tanstack.

-sh -mkdir tanstack -

-2. Enter the directory and clone this repo and the repo of the project there.
+2. Install dependencies and start the dev server:

-cd tanstack
-git clone git@github.com:TanStack/tanstack.com.git
-git clone git@github.com:TanStack/form.git
+pnpm install
+pnpm dev

-> [!NOTE]
-> Your tanstack directory should look like this:
->
-> -> tanstack/ -> | -> +-- form/ -> | -> +-- tanstack.com/ ->

-> [!WARNING]
-> Make sure the name of the directory in your local file system matches the name of the project's repo. For example, tanstack/form must be cloned into form (this is the default) instead of some-other-name, because that way, the doc pages won't be found.

-3. Enter the tanstack/tanstack.com directory, install the dependencies and run the app in dev mode:
+3. Open the application at http://localhost:3000

-sh -cd tanstack.com -pnpm i -# The app will run on https://localhost:3000 by default -pnpm dev -
+4. View traces in Jaeger at http://localhost:16686

-4. Now you can visit http://localhost:3000/form/latest/docs/overview in the browser and see the changes you make in tanstack/form/docs.
+## Resources

-> [!NOTE]
-> The updated pages need to be manually reloaded in the browser.

-> [!WARNING]
-> You will need to update the docs/config.json file (in the project's repo) if you add a new doc page!
+- TanStack Router Docs
+- OpenTelemetry JavaScript
+- Jaeger


<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 LanguageTool</summary>

[uncategorized] ~25-~25: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...TanStack Router app. In production, the markdown doc pages are fetched from the GitHub r...

(MARKDOWN_NNP)

---

[style] ~71-~71: Using many exclamation marks might seem excessive (in this case: 8 exclamation marks for a text that’s 1725 characters long)
Context: ...e manually reloaded in the browser.  > [!WARNING] > You will need to update the `docs/config.json` file (in the project's repo) if you add a new doc page! 

(EN_EXCESSIVE_EXCLAMATION)

</details>
<details>
<summary>🪛 markdownlint-cli2 (0.18.1)</summary>

46-46: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

---

53-53: Blank line inside blockquote

(MD028, no-blanks-blockquote)

---

66-66: Bare URL used

(MD034, no-bare-urls)

---

70-70: Blank line inside blockquote

(MD028, no-blanks-blockquote)

</details>

</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

In examples/react/start-otel/README.md around lines 1-72, the README currently
contains the tanstack.com docs workflow instead of documentation for the
OpenTelemetry example; replace that top section with a focused OTEL README that
explains what the example demonstrates (OpenTelemetry + TanStack Router
instrumentation patterns), how to run it (pnpm install, pnpm dev), how to start
Jaeger (docker-compose up -d), where to view traces (http://localhost:16686) and
any specific instrumentation patterns used (e.g., router span creation, manual
spans for loaders/actions), and add a short Resources section linking to
TanStack Router docs, OpenTelemetry JS, and Jaeger.


</details>

<!-- This is an auto-generated comment by CodeRabbit -->

Comment on lines +1 to +4
import { createFileRoute } from '@tanstack/react-router'
import { NotFound } from 'src/components/NotFound'
import { UserErrorComponent } from 'src/components/UserError'
import type { User } from '../utils/users'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Make notFoundComponent reachable and align import aliases.

On a 404, throw notFound() and preserve it through the catch; otherwise the notFoundComponent never renders. Also align imports to the "~" alias used elsewhere.

-import { createFileRoute } from '@tanstack/react-router'
-import { NotFound } from 'src/components/NotFound'
-import { UserErrorComponent } from 'src/components/UserError'
+import { createFileRoute, isNotFound, notFound } from '@tanstack/react-router'
+import { NotFound } from '~/components/NotFound'
+import { UserErrorComponent } from '~/components/UserError'
 import type { User } from '../utils/users'

 export const Route = createFileRoute('/users/$userId')({
   loader: async ({ params: { userId } }) => {
-    try {
-      const res = await fetch('/api/users/' + userId)
-      if (!res.ok) {
-        throw new Error('Unexpected status code')
-      }
-
-      const data = await res.json()
-
-      return data as User
-    } catch {
-      throw new Error('Failed to fetch user')
-    }
+    try {
+      const res = await fetch('/api/users/' + userId)
+      if (res.status === 404) {
+        throw notFound()
+      }
+      if (!res.ok) {
+        throw new Error('Unexpected status code')
+      }
+      const data = (await res.json()) as User
+      return data
+    } catch (e) {
+      if (isNotFound(e)) throw e
+      throw new Error('Failed to fetch user')
+    }
   },
   errorComponent: UserErrorComponent,
   component: UserComponent,
   notFoundComponent: () => {
     return <NotFound>User not found</NotFound>
   },
 })

Also applies to: 6-20

🤖 Prompt for AI Agents
In examples/react/start-otel/src/routes/users.$userId.tsx around lines 1-4 (and
also apply to lines 6-20), the route loader currently doesn't throw notFound()
on a 404 and the imports use relative paths instead of the project "~" alias;
update the loader to detect a 404 and throw notFound() so the react-router
notFoundComponent can render, and ensure any try/catch preserves and rethrows
notFound() (i.e., if (response.status === 404) throw notFound(); catch(e){ if
(isNotFound(e)) throw e; throw e; }), and change imports to use the "~" alias
(e.g., import { NotFound } from '~/components/NotFound' and import {
UserErrorComponent } from '~/components/UserError') so aliasing matches the rest
of the codebase.

Comment on lines +1 to +5
import handler from '@tanstack/react-start/server-entry'
import { tracer } from './utils/tracer'

import './otel'

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Initialize OTEL before obtaining a tracer.

Import './otel' first to ensure the SDK/provider is registered before any tracer is requested.

-import handler from '@tanstack/react-start/server-entry'
-import { tracer } from './utils/tracer'
-
-import './otel'
+import './otel'
+import handler from '@tanstack/react-start/server-entry'
+import { tracer } from './utils/tracer'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import handler from '@tanstack/react-start/server-entry'
import { tracer } from './utils/tracer'
import './otel'
import './otel'
import handler from '@tanstack/react-start/server-entry'
import { tracer } from './utils/tracer'
🤖 Prompt for AI Agents
In examples/react/start-otel/src/server.ts around lines 1 to 5, the
OpenTelemetry SDK is initialized after the tracer is imported which can cause
the tracer to be obtained before the provider is registered; move the
side-effect import import './otel' to the top of the file so it runs before
importing or using the tracer (i.e., ensure './otel' is imported first, then
import { tracer } and the handler).

Comment on lines +12 to +14
export const fetchPost = createServerFn({ method: 'POST' })
.inputValidator((d: string) => d)
.handler(async ({ data, context }) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Strengthen input validation for postId.

Coerce to positive int; reject invalid values.

 export const fetchPost = createServerFn({ method: 'POST' })
-  .inputValidator((d: string) => d)
+  .inputValidator((d: string) => {
+    const id = Number.parseInt(d, 10)
+    if (!Number.isFinite(id) || id <= 0) {
+      throw new Error('Invalid post id')
+    }
+    return id
+  })
   .handler(async ({ data, context }) => {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const fetchPost = createServerFn({ method: 'POST' })
.inputValidator((d: string) => d)
.handler(async ({ data, context }) => {
export const fetchPost = createServerFn({ method: 'POST' })
.inputValidator((d: string) => {
const id = Number.parseInt(d, 10)
if (!Number.isFinite(id) || id <= 0) {
throw new Error('Invalid post id')
}
return id
})
.handler(async ({ data, context }) => {
🤖 Prompt for AI Agents
In examples/react/start-otel/src/utils/posts.tsx around lines 12 to 14, the
inputValidator currently accepts any string; change it to coerce the incoming
postId to a positive integer and reject invalid values. Update the
inputValidator to parse the string (e.g., Number or parseInt), ensure it is an
integer > 0, and return the coerced number; if parsing fails or the value is not
a positive integer, throw or return a validation error so the handler never
receives invalid postId. Also adjust the handler signature/use to expect the
validated numeric postId rather than a raw string.

export const fetchPost = createServerFn({ method: 'POST' })
.inputValidator((d: string) => d)
.handler(async ({ data, context }) => {
console.log('Request context:', context)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Do not log entire request context (may contain sensitive data).

This risks leaking headers/cookies/PII into logs.

-    console.log('Request context:', context)
+    if (import.meta.env.DEV) {
+      console.log('Request context:', context)
+    }

Run to find any other sensitive context/header logs:


🏁 Script executed:

#!/bin/bash
rg -n --glob "examples/react/start-otel/**" -C2 -e "Request context:" -e "getRequestHeaders\("

Length of output: 954


Now I need to inspect the actual code to understand context better:

Based on my verification, I have confirmed that:

  1. The context object may include cookies used in authentication, and the request object can be used to get the url, headers, method, and even the body of the request.
  2. The script execution found two locations with sensitive logging: examples/react/start-otel/src/utils/posts.tsx:15 and examples/react/start-otel/src/routes/api/users.ts:8.

The original review comment only addresses one location. However, the verification revealed a second identical issue in users.ts that should also be fixed.


Sensitive logging in request context and headers must be restricted to development only.

Both locations log complete request objects containing authentication headers and cookies:

  • examples/react/start-otel/src/utils/posts.tsx line 15: console.log('Request context:', context)
  • examples/react/start-otel/src/routes/api/users.ts line 8: console.info('Request Headers:', getRequestHeaders())

Wrap both logs in a development check to prevent leaking sensitive credentials:

- console.log('Request context:', context)
+ if (import.meta.env.DEV) {
+   console.log('Request context:', context)
+ }
- console.info('Request Headers:', getRequestHeaders())
+ if (import.meta.env.DEV) {
+   console.info('Request Headers:', getRequestHeaders())
+ }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
console.log('Request context:', context)
if (import.meta.env.DEV) {
console.log('Request context:', context)
}
🤖 Prompt for AI Agents
In examples/react/start-otel/src/utils/posts.tsx around line 15 and
examples/react/start-otel/src/routes/api/users.ts around line 8, two console
logs output full request context/headers (which may include auth cookies and
headers); wrap both logging statements in an environment check so they only run
in development (e.g., if process.env.NODE_ENV === 'development' or
import.meta.env.DEV depending on runtime), and limit what is logged to
non-sensitive fields or a redacted summary instead of the full request object.

Comment on lines +12 to +30
const tags = [
{ title },
{ name: 'description', content: description },
{ name: 'keywords', content: keywords },
{ name: 'twitter:title', content: title },
{ name: 'twitter:description', content: description },
{ name: 'twitter:creator', content: '@tannerlinsley' },
{ name: 'twitter:site', content: '@tannerlinsley' },
{ name: 'og:type', content: 'website' },
{ name: 'og:title', content: title },
{ name: 'og:description', content: description },
...(image
? [
{ name: 'twitter:image', content: image },
{ name: 'twitter:card', content: 'summary_large_image' },
{ name: 'og:image', content: image },
]
: []),
]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Filter out meta tags with undefined content values.

The function includes meta tags with potentially undefined content values (description, keywords) in the returned array. Most meta tag implementations expect either the tag to be omitted or the content to be a string, not undefined.

Apply this diff to filter out tags with undefined content:

 export const seo = ({
   title,
   description,
   keywords,
   image,
 }: {
   title: string
   description?: string
   image?: string
   keywords?: string
 }) => {
   const tags = [
     { title },
-    { name: 'description', content: description },
-    { name: 'keywords', content: keywords },
+    ...(description ? [{ name: 'description', content: description }] : []),
+    ...(keywords ? [{ name: 'keywords', content: keywords }] : []),
     { name: 'twitter:title', content: title },
-    { name: 'twitter:description', content: description },
+    ...(description ? [{ name: 'twitter:description', content: description }] : []),
     { name: 'twitter:creator', content: '@tannerlinsley' },
     { name: 'twitter:site', content: '@tannerlinsley' },
     { name: 'og:type', content: 'website' },
     { name: 'og:title', content: title },
-    { name: 'og:description', content: description },
+    ...(description ? [{ name: 'og:description', content: description }] : []),
     ...(image
       ? [
           { name: 'twitter:image', content: image },
           { name: 'twitter:card', content: 'summary_large_image' },
           { name: 'og:image', content: image },
         ]
       : []),
   ]
 
   return tags
 }
🤖 Prompt for AI Agents
In examples/react/start-otel/src/utils/seo.ts around lines 12-30, the tags array
currently includes objects whose content may be undefined (e.g., description,
keywords); update the function to remove any tag objects that have an undefined
or null content before returning/using the array. Concretely, build the tags as
you do now, then filter them to only include entries where the content property
is a defined string (keep the title object as-is if it has no content field), so
meta tags with undefined content are omitted.

@ifxnas
Copy link

ifxnas commented Oct 27, 2025

Update on this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants