447 lines
13 KiB
Markdown
447 lines
13 KiB
Markdown
# 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**:
|
|
```typescript
|
|
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](https://community.openai.com/t/error-running-thread-already-has-an-active-run/782118)
|
|
|
|
---
|
|
|
|
## 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**:
|
|
```typescript
|
|
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**:
|
|
```typescript
|
|
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](https://community.openai.com/t/assistants-api-file-search-and-vector-stores/863944)
|
|
|
|
---
|
|
|
|
## 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
|
|
|
|
```typescript
|
|
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**:
|
|
```typescript
|
|
// 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](https://tmmtt.medium.com/openai-assistant-api-with-code-interpreter-e7f382bff83e)
|
|
|
|
---
|
|
|
|
## 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**:
|
|
```typescript
|
|
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**:
|
|
```typescript
|
|
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**:
|
|
```typescript
|
|
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](https://community.openai.com/t/streaming-stopped-at-thread-run-requires-action-when-handling-openai-assistants-function-calling/943674)
|
|
|
|
---
|
|
|
|
## 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_bytes` regularly
|
|
- **Delete unused stores**: Clean up old vector stores
|
|
- **Batch operations**: Use batch file uploads instead of individual uploads
|
|
|
|
```typescript
|
|
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**:
|
|
```typescript
|
|
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
|
|
|
|
```typescript
|
|
// ❌ 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**:
|
|
```typescript
|
|
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**:
|
|
- [OpenAI Assistants API Docs](https://platform.openai.com/docs/assistants)
|
|
- [OpenAI Community Forum](https://community.openai.com/c/api/assistants-api/49)
|
|
- [API Reference](https://platform.openai.com/docs/api-reference/assistants)
|