PROBLEM:
DefaultChatTransport body is cloned ONCE on mount, so env vars
were always empty {} even after localStorage loaded them.
SOLUTION:
Use a function for body instead of an object. AI SDK v6 calls
body() on each request, ensuring latest env vars are sent.
Changes:
- useChat.ts: body: { env } → body: () => ({ env: buildEnvObject() })
- buildEnvObject() is called fresh on each request
- Env vars now sent correctly to /api/chat
Credit: ChatGPT for identifying the exact AI SDK v6 pattern
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2.7 KiB
Environment Variables Not Sent to API - Frontend Transport Issue
Problem
Environment variables saved in localStorage are NOT being sent to /api/chat endpoint.
Evidence from logs:
📥 Request body: {
"conversationId": "7xur5hf1GDSOQMgFYF-l7",
"env": {}, // ❌ EMPTY - should have FIRECRAWL_API_KEY
...
}
Root Cause
The issue is in apps/playground/src/hooks/useChat.ts:
export function useChat() {
const [conversationId] = useState(() => nanoid());
const envVars = useEnvVars(); // ❌ Empty on first render (useEffect loads async)
const envObject = envVars.reduce(
(acc, { key, value }) => {
acc[key] = value;
return acc;
},
{} as Record<string, string>
);
const chat = useAISDKChat({
transport: new DefaultChatTransport({ // ❌ Created ONCE with empty envObject
api: '/api/chat',
body: {
conversationId,
env: envObject, // ❌ This is {} on first render, never updates
},
}),
});
return { ...chat, conversationId };
}
Why it fails:
useEnvVars()loads from localStorage inside auseEffect(async)- On first render,
envVars = [], soenvObject = {} DefaultChatTransportis created withbody: { env: {} }- Even when
envVarsupdates later, the transport is already created and doesn't re-create
Attempted Solutions That Don't Work
❌ Just updating state - Transport is created once and cached ❌ Using useEffect - Transport is already created before effect runs
What We Need
The body field in DefaultChatTransport needs to be dynamic and read the latest env vars on each request, not just once during component mount.
Questions for ChatGPT
-
How do we make
DefaultChatTransportbody dynamic? Can we pass a function instead of an object? -
Does AI SDK have a way to update transport body between messages? The env vars might change while the chat is open.
-
Should we use a custom transport instead? Can we implement our own transport that reads env vars fresh on each request?
-
Alternative: Can we manually add env to each message? Is there a way to inject extra data per-request instead of per-transport?
Current Code Files
apps/playground/src/hooks/useChat.ts- The broken hookapps/playground/src/components/sidebar/SettingsSidebar.tsx- Where env vars are stored (works fine)apps/playground/src/app/api/chat/route.ts- Server expectsbody.envbut receives{}
What We Know Works
✅ Saving env vars to localStorage - working ✅ Reading env vars from localStorage - working ✅ Server accepting and using env vars - working ❌ Sending env vars from client to server - BROKEN
The ONLY broken part is the transport not sending the latest env object.