bytedance/deer-flow · error
Thread is not ready for file upload.
Error message
Thread is not ready for file upload.
What it means
Guard inside the send path: attachments are converted to File objects first, and only then is threadId checked. If the thread id is falsy (empty string, null, undefined) at that point, the upload cannot be addressed to /api/threads/{id}/uploads, so it throws instead of uploading to nowhere.
Source
Thrown at frontend/src/core/threads/hooks.ts:2145
try {
const filePromises = message.files.map((fileUIPart) =>
promptInputFilePartToFile(fileUIPart),
);
const conversionResults = await Promise.all(filePromises);
const files = conversionResults.filter(
(file): file is File => file !== null,
);
const failedConversions = conversionResults.length - files.length;
if (failedConversions > 0) {
throw new Error(
`Failed to prepare ${failedConversions} attachment(s) for upload. Please retry.`,
);
}
if (!threadId) {
throw new Error("Thread is not ready for file upload.");
}
if (files.length > 0) {
const uploadResponse = await uploadFiles(threadId, files);
uploadedFileInfo = uploadResponse.files;
// Update optimistic human message with uploaded status + paths
const uploadedFiles: FileInMessage[] = uploadedFileInfo.map(
(info) => ({
filename: info.filename,
size: info.size,
path: info.virtual_path,
status: "uploaded" as const,
}),
);
setOptimisticMessages((messages) => {
if (messages.length > 1 && messages[0]) {
const humanMessage: Message = messages[0];View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Await thread id creation before enabling send-with-attachments (disable the attach/send button until threadId is truthy).
- If sending on a new thread, create the thread first, then run the upload+send sequence with the resolved id.
- Check for a deleted/switched thread: cancel the in-flight send when the active thread id changes.
Example fix
// before: send proceeds with a possibly-empty id
await sendMessage({ ...message, files });
// after: gate the send on the resolved thread id
const threadId = await ensureThreadCreated();
if (!threadId) { throw new Error('Thread is not ready for file upload.'); }
await sendMessage({ ...message, files }); Defensive patterns
Strategy: validation
Validate before calling
if (!threadId) { /* block send-with-attachments in the UI: disable attach button or create thread first */ } Type guard
function isReadyForUpload(threadId: unknown): threadId is string {
return typeof threadId === "string" && threadId.length > 0;
} Try / catch
catch (e) { if (e.message === "Thread is not ready for file upload.") { await ensureThreadCreated(); /* retry once */ } else throw e; } Prevention
- Create the thread before enabling attachment send on new threads.
- Cancel in-flight sends when the active thread id changes.
- Type the send path so threadId is non-null by construction (create-then-send sequence).
When it happens
Trigger: User sends a message with files before the thread has been created/server-assigned — e.g. an optimistic send on a brand-new thread whose id promise has not resolved, or a send triggered from a stale component after thread deletion cleared the id.
Common situations: Race on first message in a new thread (title/id creation still in flight), a component holding a stale threadId after switching threads mid-upload, or a demo/static thread that has no server id.
Related errors
- Failed to prepare ${failedConversions} attachment(s) for upl
- Upload failed
- Failed to create side conversation.
- Failed to load thread token usage.
- Failed to branch conversation.
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/2d75598227f8d88e.
Report an issue: GitHub.