I’m running into an issue I’m unsure of how to debug or even how to begin.
When making an API request to either my OpenAI or ReplicateAI on the local dev and build version of my Next.JS application I keep triggering a 500 error with a TypeError: ReadableStream: Expected <ref *1> ReadableStream
. See Reference #1 for the full error text.
Although I receive the error it appears the request is successful. For ReplicateAI I am able to see my result in the dashboard.
This error does not exist on my deployed version and everything works as expected.
I haven’t tried much as Im not sure where to begin on this issue.
Reference #1: Error Message
[CONVERSATION_ERROR TypeError: ReadableStream: Expected <ref *1> ReadableStream {
_state: 'readable',
_reader: undefined,
_storedError: undefined,
_disturbed: false,
_readableStreamController: ReadableByteStreamController {
_controlledReadableByteStream: [Circular *1],
_pullAgain: false,
_pulling: false,
_byobRequest: null,
_queueTotalSize: 0,
_queue: SimpleQueue {
_cursor: 0,
_size: 0,
_front: [Object],
_back: [Object]
},
_closeRequested: false,
_started: false,
_strategyHWM: 0,
_pullAlgorithm: [Function: pullAlgorithm],
_cancelAlgorithm: [Function: cancelAlgorithm],
_autoAllocateChunkSize: undefined,
_pendingPullIntos: SimpleQueue {
_cursor: 0,
_size: 0,
_front: [Object],
_back: [Object]
}
}
} to be an instance of ReadableStream.
at webidl.errors.exception (node:internal/deps/undici/undici:1679:14)
at Object.ReadableStream (node:internal/deps/undici/undici:1878:31)
at webidl.converters.BodyInit (node:internal/deps/undici/undici:4688:34)
at new Response (node:internal/deps/undici/undici:4396:36)
at new NextResponse (webpack-internal:///(rsc)/./node_modules/next/dist/server/web/spec-extension/response.js:38:9)
at NextResponse.json (webpack-internal:///(rsc)/./node_modules/next/dist/server/web/spec-extension/response.js:67:16)
at POST (webpack-internal:///(rsc)/./app/api/conversation/route.ts:48:99)
at async /Users/myName/Documents/Coding/myProject/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:6:61466
✓ Compiled /(dashboard)/(routes)/music/page in 686ms (1838 modules)
✓ Compiled /api/music/route in 170ms (883 modules)
[MUSIC_ERROR TypeError: ReadableStream: Expected <ref *1> ReadableStream {
_state: 'readable',
_reader: undefined,
_storedError: undefined,
_disturbed: false,
_readableStreamController: ReadableByteStreamController {
_controlledReadableByteStream: [Circular *1],
_pullAgain: false,
_pulling: false,
_byobRequest: null,
_queueTotalSize: 0,
_queue: SimpleQueue {
_cursor: 0,
_size: 0,
_front: [Object],
_back: [Object]
},
_closeRequested: false,
_started: false,
_strategyHWM: 0,
_pullAlgorithm: [Function: pullAlgorithm],
_cancelAlgorithm: [Function: cancelAlgorithm],
_autoAllocateChunkSize: undefined,
_pendingPullIntos: SimpleQueue {
_cursor: 0,
_size: 0,
_front: [Object],
_back: [Object]
}
}
} to be an instance of ReadableStream.
at webidl.errors.exception (node:internal/deps/undici/undici:1679:14)
at Object.ReadableStream (node:internal/deps/undici/undici:1878:31)
at webidl.converters.BodyInit (node:internal/deps/undici/undici:4688:34)
at new Response (node:internal/deps/undici/undici:4396:36)
at new NextResponse (webpack-internal:///(rsc)/./node_modules/next/dist/server/web/spec-extension/response.js:38:9)
at NextResponse.json (webpack-internal:///(rsc)/./node_modules/next/dist/server/web/spec-extension/response.js:67:16)
at POST (webpack-internal:///(rsc)/./app/api/music/route.ts:47:99)
at async /Users/MyName/Documents/Coding/MyProject/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:6:61466
Reference #2: My Route Code
import { auth } from '@clerk/nextjs';
import { NextResponse } from 'next/server';
import OpenAI from 'openai';
import { increaseApiLimit, checkApiLimit } from '@/lib/api-limit';
import { checkSubscription } from '@/lib/subscription';
const openai = new OpenAI({
apiKey: process.env.OPEN_API_KEY,
});
export async function POST(req: Request) {
try {
const { userId } = auth();
const body = await req.json();
const { messages } = body;
if (!userId) {
return new NextResponse("Unauthorized", { status: 401 })
}
if(!openai.apiKey) {
return new NextResponse("openai API Key not configured")
}
if (!messages) {
return new NextResponse("Messages are required", { status: 400 })
}
const freeTrial = await checkApiLimit();
const isPro = await checkSubscription();
if (!freeTrial && !isPro) {
return new NextResponse("Free trial has expired.", {
status: 403
})
}
const response = await openai.chat.completions.create({
model: "gpt-3.5-turbo",
messages
})
if (!isPro) await increaseApiLimit();
return NextResponse.json(response.choices[0].message)
} catch (error) {
console.log('[CONVERSATION_ERROR', error);
return new NextResponse('Internal error', { status: 500 });
}
}
Reference #3: Form to make the request
'use client';
import axios from 'axios';
import { toast } from 'react-hot-toast';
import { Empty } from '@/components/Empty';
import { Loader } from '@/components/Loader';
import Heading from '@/components/Heading';
import { MessageSquare } from 'lucide-react';
import { useForm } from 'react-hook-form';
import * as z from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
import { formSchema } from './constants';
import { Form, FormControl, FormField, FormItem } from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import { useRouter } from 'next/navigation';
import { useState } from 'react';
import { ChatCompletionMessageParam } from 'openai/resources/index.mjs';
import { cn } from '@/lib/utils';
import { UserAvatar } from '@/components/UserAvatar';
import { BotAvatar } from '@/components/BotAvatar';
import useProModal from '@/hooks/useProModal';
const ConversationPage = () => {
const [messages, setMessages] = useState<ChatCompletionMessageParam[]>([]);
const router = useRouter();
const proModal = useProModal();
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
prompt: '',
},
});
const isResponseLoading = form.formState.isSubmitting;
const onSubmit = async (values: z.infer<typeof formSchema>) => {
try {
const userMessage: ChatCompletionMessageParam = {
role: 'user',
content: values.prompt,
};
const newMessages = [...messages, userMessage];
const response = await axios.post('/api/conversation', {
messages: newMessages,
});
setMessages((current) => [...current, userMessage, response.data]);
form.reset();
} catch (error: any) {
if (error?.response?.status === 403) {
proModal.onOpen();
} else {
toast.error("Something went wrong");
}
} finally {
router.refresh();
}
};
return (
<div>
<Heading
title='Conversation'
description='Our most advanced conversation model.'
Icon={MessageSquare}
iconColor='text-violet-500'
bgColor='bg-violet-500/10'
/>
<div className='px-4 lg:px-8'>
<div>
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className='
rounded-lg
border
w-full
p-4
px-3
md:px-6
focus-within:shadow-sm
grid
grid-cols-12
gap-2
'
>
<FormField
name='prompt'
render={({ field }) => (
<FormItem className='col-span-12 lg:col-span-10'>
<FormControl className='m-0 p-0'>
<Input
className='border-0 outline-none focus-visible:ring-0 focus-visible:ring-transparent'
disabled={isResponseLoading}
placeholder='How do I calculate the radius of a circle?'
{...field}
/>
</FormControl>
</FormItem>
)}
/>
<Button
className='col-span-12 lg:col-span-2 w-full'
disabled={isResponseLoading}
>
Generate
</Button>
</form>
</Form>
</div>
<div className='space-y-4 mt-4'>
{isResponseLoading && (
<div className='p-8 rounded-lg w-full flex items-center justify-center bg-muted'>
<Loader />
</div>
)}
{messages.length === 0 && !isResponseLoading && (
<Empty label={'No Conversation Started'} />
)}
<div className='flex flex-col-reverse gap-y-4'>
{messages.map((message, idx) => (
<div
key={`${message.content}-${idx}`}
className={cn(
'p-8 w-full flex items-start gap-x-8 rounded-lg',
message.role === 'user'
? 'bg-white border border-black/10'
: 'bg-muted'
)}
>
{message.role === 'user' ? <UserAvatar /> : <BotAvatar />}
<p className='text-sm'>{message.content}</p>
</div>
))}
</div>
</div>
</div>
</div>
);
};
export default ConversationPage;