Get this on every PR automatically. Webhook fires, AI reviews, you approve.
Install on langchain-ai/deployment-cookbook →
// reviewed by pulllight

PullLight found 5 issues

langchain-ai/deployment-cookbook #1 — feat: add managed deepagents example by @christian-bromann Jul 16, 2026
2 high 2 medium 1 low
🔍
// convert to your repo
PullLight caught 5 2 high, 2 medium, 1 low on this PR.
Install on langchain-ai/deployment-cookbook to get this on every PR automatically — 60 seconds.
Findings
5 issues
high auth
`getApiKey()` returns `undefined` when `LANGSMITH_API_KEY` is not set, and `createManagedClient()` silently passes `{ apiKey: undefined }` to `ManagedClient`. This means all API calls (fetchThreads, createThread, deleteThread, createStreamClient) will be made without authentication, likely resulting in 401 errors at runtime rather than a clear configuration error. The missing-key case should be caught early and surfaced to the user, similar to how `requireManagedAgentId()` works for the agent ID.
// js-langsmith-managed/src/lib/chat/threads-client.ts:40
high auth
`envPrefix: ["VITE_", "LANGSMITH_"]` causes Vite to embed ALL environment variables whose names start with `LANGSMITH_` into the client bundle at build time. This includes `LANGSMITH_API_KEY`, which is a secret credential. When this app is built and deployed to Vercel (as documented in the README), the API key will be baked into the publicly-served JavaScript bundle and visible to anyone who inspects the page source. The README acknowledges this for local dev but the Vercel deployment instructions in the README also set `LANGSMITH_API_KEY` as a Vercel env var, meaning production builds will also leak the key. A backend proxy should be used instead of exposing the key via `envPrefix`.
// js-langsmith-managed/vite.config.ts:9
medium race-condition
The `initStarted` ref guard prevents double-initialization in StrictMode, but `handleDelete` (line 68) calls `createThread()` and `fetchThreads()` without any guard. If the user rapidly deletes threads, multiple concurrent `createThread` calls can fire, creating orphaned threads. Additionally, `handleDelete` closes over `threadId` in its dependency array but `refreshThreads` is not included — if `refreshThreads` identity changes (it shouldn't due to `useCallback([])`, but the pattern is fragile), stale closures could result.
// js-langsmith-managed/src/components/ChatApp.tsx:47
low other
`threadId` is declared as a required prop in the type signature (`{ threadId: string; onRunSettled: () => void }`) but is never used inside the component body — the actual thread ID is consumed by `useStreamContext` via the `StreamProvider` wrapping this component. The unused prop is harmless but misleading; TypeScript's `noUnusedParameters` in `tsconfig.app.json` should flag this.
// js-langsmith-managed/src/components/Chat.tsx:17
medium error-handling
`fetchThreads` silently swallows all errors with a bare `catch { return []; }`. If the API key is wrong or the network is down, the sidebar will appear empty with no indication of failure, and the `initStarted` guard in `ChatApp` will then call `createThread()` (which will also fail, this time with an unhandled rejection propagating to the caller). The error should at minimum be logged, and ideally distinguished from the "no threads yet" case so the UI can show a meaningful error state.
// js-langsmith-managed/src/lib/chat/threads-client.ts:119
model: claude-sonnet-4-5   input: 31140 tokens   output: 1197 tokens