The Node.js-specific HostDetector
from @opentelemetry/resources
is being imported in a Cloudflare Workers test environment, causing compatibility issues.
Error Location: /Users/schickling/Code/livestore/cloudflare-adapter/node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@opentelemetry/resources/build/esm/detectors/platform/node/HostDetector.js
Test File: /Users/schickling/Code/livestore/cloudflare-adapter/tests/integration-cloudflare/src/hibernation.test.ts
hibernation.test.ts
→SELF
fromcloudflare:test
- Cloudflare Worker →
@livestore/adapter-cloudflare
→make-durable-object.ts
make-durable-object.ts
→makeAdapter()
from./make-adapter.ts
make-adapter.ts:143
→Effect.withSpan()
(and other Effect utilities)@livestore/utils/effect/index.ts:3
→export * as OtelTracer from '@effect/opentelemetry/Tracer'
← ROOT CAUSE@effect/opentelemetry/Resource.js:1
→import * as Resources from "@opentelemetry/resources"
@opentelemetry/resources/index.js:17
→hostDetector
from./detectors
@opentelemetry/resources/detectors/platform/index.js:16
→ Node.js platform detectors@opentelemetry/resources/detectors/platform/node/HostDetector.js
← The problematic Node.js-specific code
export * as OtelTracer from '@effect/opentelemetry/Tracer' // ← ROOT CAUSE
import * as OtelTracer from '@effect/opentelemetry/Tracer' // ← Uses OtelTracer
// Used in tapCauseLogPretty function
const span = yield* OtelTracer.currentOtelSpan.pipe(
Effect.catchTag('NoSuchElementException', (_) => Effect.succeed(undefined)),
)
Effect.withSpan('@livestore/adapter-cloudflare:adapter') // ← Triggers the import chain
// This no-op implementation doesn't help because imports happen at module level
const provideOtel =
(_options: { otelTracer?: any; parentSpanContext?: any }) =>
<A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> => {
return effect // No-op for Cloudflare Workers
}
The provideOtel
no-op function in make-durable-object.ts
doesn't prevent the issue because:
- Module-level imports: The
@effect/opentelemetry/Tracer
import happens when the module is loaded - Transitive dependencies: The import chain goes through multiple levels before reaching the Node.js-specific code
- Static analysis: Bundlers and module loaders process all imports regardless of runtime usage
@opentelemetry/resources
├── index.js (exports hostDetector)
├── detectors/
│ ├── index.js (re-exports platform detectors)
│ └── platform/
│ ├── index.js (exports from ./node)
│ └── node/
│ ├── HostDetector.js ← PROBLEMATIC FILE
│ ├── OSDetector.js
│ └── ProcessDetector.js
// @effect/opentelemetry/Resource.js:1
import * as Resources from "@opentelemetry/resources"; // Imports ALL detectors including Node.js ones
1. Cloudflare Workers SDK Issue #6581 ⭐ DIRECTLY RELATED
- Title: "🐛 BUG vitest-pool-workers loads opentelemetry for Node not the browser"
- URL: cloudflare/workers-sdk#6581
- Description: When running tests with vitest-pool-workers, it loads the Node.js version of OpenTelemetry instead of the browser/worker-compatible version
- Status: This is the exact same issue you're experiencing
2. OpenTelemetry JS Issue #4425
- Title: "How to expose Prometheus metrics for Cloudflare workers (serverless/lambda-like)"
- URL: open-telemetry/opentelemetry-js#4425
- Description: Discusses compatibility issues with OpenTelemetry in serverless environments including Cloudflare Workers
3. OpenTelemetry JS Issue #1214
- Title: "Service Worker Spec"
- URL: open-telemetry/opentelemetry-js#1214
- Description: Addresses compatibility with service worker environments (which Cloudflare Workers implement)
1. Specialized OpenTelemetry Package for Cloudflare Workers
- Package:
@microlabs/otel-cf-workers
(formerlyotel-cf-workers
) - Author: Erwin van der Koogh created this package specifically for Cloudflare Workers
- Usage:
npm i @opentelemetry/api @microlabs/otel-cf-workers
- Benefit: Handles all the compatibility issues with standard OpenTelemetry in Workers environment
2. Required Configuration All solutions require adding Node.js compatibility flag:
# wrangler.toml
compatibility_flags = ["nodejs_compat"]
compatibility_date = "2024-09-23" # or later
3. Common Compatibility Issues Identified
- Platform-specific APIs: Standard OpenTelemetry libraries access APIs not available in Workers (
window.crypto
,performance
API) - Module Resolution: Node.js built-in modules (
http
,fs
, etc.) aren't available in Workers - Resource Detectors: Node.js-specific detectors (HostDetector, ProcessDetector, OSDetector) don't work in Workers
- XHR and Window References: Some OpenTelemetry implementations use browser-specific APIs that don't work in v8 isolates
The vitest-pool-workers testing environment has specific challenges:
- It loads Node.js versions of packages instead of worker-compatible versions
- This affects both development and testing workflows
- The issue occurs during test execution but not during dev server or deployment
Create separate effect utilities for different environments:
// @livestore/utils/effect/index.cloudflare.ts
export * as OtelTracer from './NoopTracer' // Use noop tracer for Cloudflare
// @livestore/utils/effect/index.node.ts
export * as OtelTracer from '@effect/opentelemetry/Tracer' // Full OpenTelemetry for Node.js
Replace @effect/opentelemetry
with @microlabs/otel-cf-workers
:
// For Cloudflare Workers builds
import { trace } from '@microlabs/otel-cf-workers'
// @livestore/utils-cloudflare/effect/index.ts
// Re-export everything from utils/effect except OpenTelemetry
export * from '@livestore/utils/effect'
export * as OtelTracer from '@livestore/utils/NoopTracer' // Override with noop
// Conditional import based on environment
const OtelTracer = typeof globalThis.document === 'undefined' && typeof process \!== 'undefined'
? await import('@effect/opentelemetry/Tracer')
: await import('./NoopTracer')
Configure your bundler to exclude Node.js-specific OpenTelemetry modules for Cloudflare builds:
// webpack.config.js / esbuild / etc.
externals: {
'@opentelemetry/resources': 'commonjs @opentelemetry/resources/browser'
}
Option 1 (environment-based imports) or Option 2 (using @microlabs/otel-cf-workers
) are recommended because they:
- Cleanly separate concerns between environments
- Maintain full OpenTelemetry functionality in Node.js
- Eliminate the import chain issue in Cloudflare
- Follow established community patterns for this exact problem
- Address the root cause identified in Cloudflare Workers SDK Issue #6581
/packages/@livestore/utils/src/effect/index.cloudflare.ts
(new)/packages/@livestore/adapter-cloudflare/src/make-adapter.ts
(update import)- Build configuration to use the correct entry point per environment
- Or alternatively: Replace
@effect/opentelemetry
with@microlabs/otel-cf-workers
for Cloudflare builds
Investigation Date: 2025-01-22
Issue: Node.js HostDetector imported in Cloudflare Workers context
Root Cause: Static import of @effect/opentelemetry/Tracer
in utils package
Impact: Build/runtime errors in Cloudflare Workers environment
Community Status: Well-documented issue with established solutions
Related Issue: Cloudflare Workers SDK #6581 (vitest-pool-workers OpenTelemetry compatibility)
EOF < /dev/null