Files
2025-11-30 08:25:15 +08:00

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_bytes regularly
  • 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: