13 KiB
Top 12 Errors - OpenAI Assistants API
Last Updated: 2025-10-25
This document catalogs the most common errors encountered when working with the Assistants API v2 and their solutions.
1. Thread Already Has Active Run
Error Message:
Error: 400 Can't add messages to thread_xxx while a run run_xxx is active.
Cause: Trying to create a new run or add messages while another run is still processing (status: queued, in_progress, or cancelling).
Solution:
async function ensureNoActiveRun(threadId: string) {
const runs = await openai.beta.threads.runs.list(threadId, {
limit: 1,
order: 'desc',
});
const latestRun = runs.data[0];
if (latestRun && ['queued', 'in_progress', 'cancelling'].includes(latestRun.status)) {
// Wait for completion or cancel
await openai.beta.threads.runs.cancel(threadId, latestRun.id);
// Poll until cancelled
let run = latestRun;
while (run.status !== 'cancelled') {
await new Promise(resolve => setTimeout(resolve, 500));
run = await openai.beta.threads.runs.retrieve(threadId, run.id);
}
}
}
Prevention: Always check for active runs before creating new ones.
Source: OpenAI Community
2. Run Polling Timeout
Error: Run never completes within reasonable polling window (300+ seconds).
Cause: Long-running tasks (complex code execution, large file processing) exceed expected completion time.
Solution:
async function pollWithTimeout(threadId: string, runId: string, maxSeconds = 300) {
const startTime = Date.now();
while (true) {
const run = await openai.beta.threads.runs.retrieve(threadId, runId);
if (!['queued', 'in_progress'].includes(run.status)) {
return run;
}
const elapsed = (Date.now() - startTime) / 1000;
if (elapsed > maxSeconds) {
await openai.beta.threads.runs.cancel(threadId, runId);
throw new Error(`Run exceeded timeout of ${maxSeconds}s`);
}
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
Prevention: Set appropriate timeouts and use streaming for better UX.
3. Vector Store Indexing Delay
Error: File search returns no results despite files being uploaded.
Cause: Using vector store before indexing completes (async process).
Solution:
async function waitForVectorStore(vectorStoreId: string) {
let store = await openai.beta.vectorStores.retrieve(vectorStoreId);
while (store.status === 'in_progress') {
await new Promise(resolve => setTimeout(resolve, 2000));
store = await openai.beta.vectorStores.retrieve(vectorStoreId);
console.log(`Indexing: ${store.file_counts.completed}/${store.file_counts.total}`);
}
if (store.status === 'failed') {
throw new Error('Vector store indexing failed');
}
return store; // status: 'completed'
}
Prevention: Always wait for status: "completed" before using vector store with assistants.
Source: OpenAI Community
4. File Search Relevance Issues
Error: File search returns irrelevant or incomplete results.
Cause: Poor document chunking, lack of context, or query optimization needed.
Solution:
- Better instructions: Guide assistant on how to use file search
- Structured documents: Use clear headers, sections, and formatting
- Metadata: Add descriptive metadata to files (coming soon)
- Query refinement: Encourage users to be specific
const assistant = await openai.beta.assistants.create({
instructions: `You are a support assistant. When answering:
1. Use file_search to find relevant documentation
2. Quote specific sections with citations
3. If information isn't found, say so clearly
4. Provide context around the answer`,
tools: [{ type: "file_search" }],
// ...
});
Prevention: Structure documents well and provide clear assistant instructions.
5. Code Interpreter File Output Not Found
Error: image_file.file_id referenced but file doesn't exist or can't be downloaded.
Cause: Files generated by Code Interpreter are temporary and may be cleaned up before retrieval.
Solution:
// Retrieve and save immediately after run completes
const messages = await openai.beta.threads.messages.list(threadId);
const responseMessage = messages.data[0];
for (const content of responseMessage.content) {
if (content.type === 'image_file') {
try {
const fileData = await openai.files.content(content.image_file.file_id);
const buffer = Buffer.from(await fileData.arrayBuffer());
fs.writeFileSync(`output_${content.image_file.file_id}.png`, buffer);
} catch (error) {
console.error('File no longer available:', error);
}
}
}
Prevention: Download generated files immediately after run completion.
Source: Medium - Code Interpreter Tutorial
6. Thread Message Limit Exceeded
Error: 400 Thread has exceeded the maximum number of messages (100,000).
Cause: Very long conversations hitting the 100k message limit.
Solution:
async function archiveAndStartNewThread(oldThreadId: string, userId: string) {
// Get conversation summary
const messages = await openai.beta.threads.messages.list(oldThreadId, {
limit: 50,
});
// Save to database
await db.archiveThread(oldThreadId, messages.data);
// Create new thread
const newThread = await openai.beta.threads.create({
metadata: {
user_id: userId,
previous_thread: oldThreadId,
},
});
return newThread.id;
}
Prevention: Archive old threads and create new ones periodically.
7. Function Calling Timeout
Error: Run expires (status: expired) while waiting for tool outputs.
Cause: Tool execution takes too long (max 10 minutes for run).
Solution:
if (run.status === 'requires_action') {
const toolCalls = run.required_action.submit_tool_outputs.tool_calls;
const toolOutputs = [];
for (const toolCall of toolCalls) {
try {
// Add timeout to function execution
const output = await Promise.race([
executeFunction(toolCall.function.name, JSON.parse(toolCall.function.arguments)),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Function timeout')), 30000)
),
]);
toolOutputs.push({
tool_call_id: toolCall.id,
output: JSON.stringify(output),
});
} catch (error) {
// Return error as output
toolOutputs.push({
tool_call_id: toolCall.id,
output: JSON.stringify({ error: error.message }),
});
}
}
await openai.beta.threads.runs.submitToolOutputs(threadId, run.id, {
tool_outputs: toolOutputs,
});
}
Prevention: Implement timeouts on function execution and return errors gracefully.
8. Streaming Run Interruption
Error: Stream connection closes unexpectedly or events stop arriving.
Cause: Network issues, server errors, or run failures.
Solution:
async function streamWithRetry(threadId: string, assistantId: string) {
try {
const stream = await openai.beta.threads.runs.stream(threadId, {
assistant_id: assistantId,
});
for await (const event of stream) {
// Handle events
if (event.event === 'error') {
throw new Error('Stream error');
}
}
} catch (error) {
console.error('Stream interrupted:', error);
// Fall back to polling
const runs = await openai.beta.threads.runs.list(threadId, {
limit: 1,
order: 'desc',
});
const run = runs.data[0];
return pollRunCompletion(threadId, run.id);
}
}
Prevention: Implement fallback to polling if streaming fails.
Source: OpenAI Community
9. Vector Store Quota Limits
Error: 429 Rate limit reached for vector store operations.
Cause: Too many vector store operations or storage exceeded.
Solution:
- Monitor storage: Check
usage_bytesregularly - Delete unused stores: Clean up old vector stores
- Batch operations: Use batch file uploads instead of individual uploads
async function cleanupOldVectorStores(keepDays = 30) {
const stores = await openai.beta.vectorStores.list({ limit: 100 });
for (const store of stores.data) {
const ageSeconds = Date.now() / 1000 - store.created_at;
const ageDays = ageSeconds / (60 * 60 * 24);
if (ageDays > keepDays) {
await openai.beta.vectorStores.del(store.id);
console.log(`Deleted vector store: ${store.id}`);
}
}
}
Prevention: Set auto-expiration on vector stores and monitor costs.
10. File Upload Format Incompatibility
Error: 400 Unsupported file type for this tool.
Cause: Uploading file format not supported by the tool.
Solution:
const SUPPORTED_FORMATS = {
code_interpreter: [
'.c', '.cpp', '.csv', '.docx', '.html', '.java', '.json', '.md',
'.pdf', '.php', '.pptx', '.py', '.rb', '.tex', '.txt', '.css',
'.jpeg', '.jpg', '.js', '.gif', '.png', '.tar', '.ts', '.xlsx', '.xml', '.zip'
],
file_search: [
'.c', '.cpp', '.docx', '.html', '.java', '.json', '.md',
'.pdf', '.php', '.pptx', '.py', '.rb', '.tex', '.txt', '.css', '.js', '.ts', '.go'
],
};
function validateFileFormat(filename: string, tool: 'code_interpreter' | 'file_search') {
const ext = filename.substring(filename.lastIndexOf('.')).toLowerCase();
if (!SUPPORTED_FORMATS[tool].includes(ext)) {
throw new Error(`Unsupported file format for ${tool}: ${ext}`);
}
}
// Validate before upload
validateFileFormat('data.csv', 'code_interpreter'); // OK
validateFileFormat('video.mp4', 'file_search'); // Throws error
Prevention: Validate file formats before uploading.
11. Assistant Instructions Token Limit
Error: 400 Instructions exceed maximum length.
Cause: Instructions field exceeds 256,000 characters (v2 limit).
Solution:
- Use file search: Put long instructions in documents
- Concise instructions: Be clear and brief
- System messages: Use thread-level messages for context
// ❌ Bad: Very long instructions
const assistant = await openai.beta.assistants.create({
instructions: "..." // 300k characters
});
// ✅ Good: Concise instructions + file search
const assistant = await openai.beta.assistants.create({
instructions: "You are a support assistant. Use file_search to find answers in the knowledge base.",
tools: [{ type: "file_search" }],
tool_resources: {
file_search: {
vector_store_ids: [vectorStoreId], // Long content here
},
},
});
Prevention: Keep instructions under 256k characters; use file search for knowledge.
12. Thread Deletion While Run Active
Error: 400 Cannot delete thread while run is active.
Cause: Attempting to delete a thread that has an active run.
Solution:
async function safeDeleteThread(threadId: string) {
// Cancel active runs first
const runs = await openai.beta.threads.runs.list(threadId);
for (const run of runs.data) {
if (['queued', 'in_progress'].includes(run.status)) {
await openai.beta.threads.runs.cancel(threadId, run.id);
// Wait for cancellation
let runStatus = run;
while (runStatus.status !== 'cancelled') {
await new Promise(resolve => setTimeout(resolve, 500));
runStatus = await openai.beta.threads.runs.retrieve(threadId, run.id);
}
}
}
// Now safe to delete
await openai.beta.threads.del(threadId);
}
Prevention: Cancel all active runs before deleting threads.
Quick Reference
| Error | Quick Fix |
|---|---|
| Thread has active run | Cancel or wait for run completion |
| Polling timeout | Set timeout and cancel long runs |
| Vector store not ready | Wait for status: "completed" |
| File search no results | Check indexing complete, improve queries |
| Code Interpreter file lost | Download immediately after run |
| 100k message limit | Archive old threads, start new ones |
| Function timeout | Add timeouts to function execution |
| Stream interrupted | Fall back to polling |
| Vector store quota | Clean up old stores, use batch uploads |
| Unsupported file format | Validate file extensions before upload |
| Instructions too long | Use file search for knowledge |
| Can't delete thread | Cancel active runs first |
Additional Resources: