Skip to content

fix: guard pino-pretty for serverless environments#1523

Open
Omramanuj wants to merge 1 commit intobrowserbase:mainfrom
Omramanuj:fix/optional-pino-pretty
Open

fix: guard pino-pretty for serverless environments#1523
Omramanuj wants to merge 1 commit intobrowserbase:mainfrom
Omramanuj:fix/optional-pino-pretty

Conversation

@Omramanuj
Copy link
Copy Markdown

@Omramanuj Omramanuj commented Jan 11, 2026

Why

Stagehand crashes in serverless environments (e.g. Vercel) when pino-pretty is not available at runtime.
pino-pretty is a dev-only formatter, but was treated as a required dependency, causing Pino to fail during initialization.

What changed

  • Moved pino-pretty to optionalDependencies
  • Guarded all pino-pretty usage with require.resolve checks
  • Ensured graceful fallback to standard logging when unavailable

Test plan

This issue cannot be reliably reproduced locally due to Node.js module resolution and pnpm hoisting.
The fix targets serverless runtimes where optional dependencies are omitted from the runtime bundle.


Summary by cubic

Prevented serverless crashes by making pino-pretty optional and guarding its usage. Logging now falls back to standard Pino output when pino-pretty isn’t available.

  • Bug Fixes

    • Guarded pino-pretty with require.resolve in core logger and Fastify server.
    • Enabled pretty transport only in development when available.
    • Fallback to standard logging when pino-pretty is missing.
  • Dependencies

    • Moved pino-pretty to optionalDependencies to avoid serverless runtime failures.

Written for commit bcba3c5. Summary will update on new commits.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Jan 11, 2026

⚠️ No Changeset found

Latest commit: bcba3c5

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 5 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/core/package.json">

<violation number="1" location="packages/core/package.json:110">
P3: Missing trailing newline at end of package.json will cause prettier --check to fail</violation>
</file>

<file name="packages/server/src/server.ts">

<violation number="1" location="packages/server/src/server.ts:56">
P2: ESM module uses undefined `require` to detect `pino-pretty`, causing silent fallback and loss of pretty logs</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Ask questions if you need clarification on any suggestion

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

}),
...(process.env.NODE_ENV === "development" && (() => {
try {
require.resolve("pino-pretty");
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Jan 11, 2026

Choose a reason for hiding this comment

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

P2: ESM module uses undefined require to detect pino-pretty, causing silent fallback and loss of pretty logs

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/server/src/server.ts, line 56:

<comment>ESM module uses undefined `require` to detect `pino-pretty`, causing silent fallback and loss of pretty logs</comment>

<file context>
@@ -51,15 +51,23 @@ const app = fastify({
-    }),
+    ...(process.env.NODE_ENV === "development" && (() => {
+      try {
+        require.resolve("pino-pretty");
+        return {
+          transport: {
</file context>
Fix with Cubic

},
"homepage": "https://stagehand.dev"
}
} No newline at end of file
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Jan 11, 2026

Choose a reason for hiding this comment

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

P3: Missing trailing newline at end of package.json will cause prettier --check to fail

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/core/package.json, line 110:

<comment>Missing trailing newline at end of package.json will cause prettier --check to fail</comment>

<file context>
@@ -107,4 +107,4 @@
   },
   "homepage": "https://stagehand.dev"
-}
+}
\ No newline at end of file
</file context>
Suggested change
}
}
Fix with Cubic

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Jan 11, 2026

Greptile Overview

Greptile Summary

This PR fixes crashes in serverless environments by making pino-pretty optional and guarding its usage with runtime checks.

Changes Made

Core Package (packages/core):

  • Moved pino-pretty from dependencies to optionalDependencies in package.json
  • Added require.resolve("pino-pretty") guard in logger.ts before attempting to use the pretty formatter
  • Graceful fallback to standard logging with a console warning when pino-pretty is unavailable

Server Package (packages/server):

  • Moved pino-pretty from dependencies to optionalDependencies in package.json
  • Added require.resolve("pino-pretty") check in Fastify logger configuration
  • Returns empty object for spread operator when pino-pretty is unavailable, falling back to standard Pino logging

How It Works

When initializing loggers:

  1. Check if pino-pretty is resolvable using require.resolve()
  2. If available: configure Pino transport to use pino-pretty formatter
  3. If unavailable: silently fall back to standard Pino output (server) or log a warning (core)

This ensures Stagehand works correctly in serverless environments like Vercel where optional dependencies are excluded from deployment bundles.

Implementation Quality

The implementation correctly addresses the issue with proper error handling and fallback behavior. The lockfile changes show that pnpm correctly marked pino-pretty and its transitive dependencies as optional.

Minor style improvements suggested: trailing whitespace cleanup and consideration of ES module-standard approaches for module resolution in the server package.

Confidence Score: 4/5

  • This PR is safe to merge with minor style improvements recommended
  • The implementation correctly solves the serverless deployment issue by making pino-pretty optional and adding proper runtime guards. All changes are well-contained to logging configuration. The lockfile shows correct optional dependency propagation. Score is 4/5 (not 5) due to: (1) trailing whitespace in server/package.json, and (2) non-standard use of require.resolve in ES module context in server.ts, though this likely works in practice with the current tooling (tsx). These are style improvements rather than functional issues.
  • packages/server/src/server.ts and packages/server/package.json need minor style improvements (ES module pattern and whitespace cleanup)

Important Files Changed

File Analysis

Filename Score Overview
packages/core/lib/logger.ts 5/5 Added require.resolve guard for pino-pretty with proper fallback. Implementation is solid and works correctly in CommonJS context.
packages/core/package.json 5/5 Correctly moved pino-pretty from dependencies to optionalDependencies. Clean change with no issues.
packages/server/package.json 4/5 Moved pino-pretty to optionalDependencies correctly, but has trailing whitespace on line 36.
packages/server/src/server.ts 4/5 Added require.resolve guard for pino-pretty, but using require in ES module context is non-standard. Consider using import.meta.resolve or createRequire.

Sequence Diagram

sequenceDiagram
    participant App as Application
    participant Logger as Logger/Fastify
    participant Node as Node.js Runtime
    participant PinoPretty as pino-pretty (optional)

    App->>Logger: Initialize logger with pretty option
    
    alt In Development/Pretty Mode
        Logger->>Node: require.resolve("pino-pretty")
        
        alt pino-pretty available
            Node-->>Logger: Module path found
            Logger->>PinoPretty: Configure pino transport
            PinoPretty-->>Logger: Pretty formatter ready
            Logger-->>App: Logger with pretty printing
        else pino-pretty not available
            Node-->>Logger: MODULE_NOT_FOUND error
            Logger->>Logger: Fallback to standard logging
            Logger-->>App: Logger with standard output
        end
    else Production/No Pretty Mode
        Logger-->>App: Logger with standard output
    end
Loading

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

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

2 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

"zod": "^4.2.0"
},
"optionalDependencies": {
"pino-pretty": "^11.3.0"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Trailing whitespace after "^11.3.0" should be removed

Suggested change
"pino-pretty": "^11.3.0"
"pino-pretty": "^11.3.0"

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/server/package.json
Line: 36:36

Comment:
Trailing whitespace after `"^11.3.0"` should be removed

```suggestion
    "pino-pretty": "^11.3.0"
```

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +54 to +70
...(process.env.NODE_ENV === "development" && (() => {
try {
require.resolve("pino-pretty");
return {
transport: {
options: {
colorize: true,
ignore: "pid,hostname",
},
target: "pino-pretty",
},
};
} catch {
// pino-pretty not available, use standard logging
return {};
}
})()),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Using require.resolve() in an ES module context (this package has "type": "module" in package.json) is non-standard. While it may work with tsx and some Node.js configurations due to CommonJS interop, it could fail in strict ES module environments or when bundled.

Consider using the ES module standard import.meta.resolve() (available in Node.js 20.6+) instead:

Suggested change
...(process.env.NODE_ENV === "development" && (() => {
try {
require.resolve("pino-pretty");
return {
transport: {
options: {
colorize: true,
ignore: "pid,hostname",
},
target: "pino-pretty",
},
};
} catch {
// pino-pretty not available, use standard logging
return {};
}
})()),
...(process.env.NODE_ENV === "development" && (async () => {
try {
await import.meta.resolve("pino-pretty");
return {
transport: {
options: {
colorize: true,
ignore: "pid,hostname",
},
target: "pino-pretty",
},
};
} catch {
// pino-pretty not available, use standard logging
return {};
}
})()),

Note: This would require adjusting the Fastify configuration to handle the async resolution, or alternatively, use createRequire from node:module:

import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);

// Then use require.resolve() as before
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/server/src/server.ts
Line: 54:70

Comment:
Using `require.resolve()` in an ES module context (this package has `"type": "module"` in package.json) is non-standard. While it may work with `tsx` and some Node.js configurations due to CommonJS interop, it could fail in strict ES module environments or when bundled.

Consider using the ES module standard `import.meta.resolve()` (available in Node.js 20.6+) instead:

```suggestion
    ...(process.env.NODE_ENV === "development" && (async () => {
      try {
        await import.meta.resolve("pino-pretty");
        return {
          transport: {
            options: {
              colorize: true,
              ignore: "pid,hostname",
            },
            target: "pino-pretty",
          },
        };
      } catch {
        // pino-pretty not available, use standard logging
        return {};
      }
    })()),
```

Note: This would require adjusting the Fastify configuration to handle the async resolution, or alternatively, use `createRequire` from `node:module`:

```typescript
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);

// Then use require.resolve() as before
```

How can I resolve this? If you propose a fix, please make it concise.

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.

1 participant