{"record":{"id":"b037d0f25297336f","repo":"different-ai/openwork","slug":"workspace-path-is-unavailable-attachments-could-n","errorCode":null,"errorMessage":"Workspace path is unavailable; attachments could not be copied for tool access.","messagePattern":"Workspace path is unavailable; attachments could not be copied for tool access\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/app/src/react-app/domains/session/sync/attachment-file-part.ts","lineNumber":347,"sourceCode":"    type: \"file\",\n    url: item.url,\n    filename: item.filename,\n    mime: modelMime,\n  };\n}\n\nexport async function composerAttachmentsToWorkspaceFileParts(input: {\n  attachments: ComposerAttachment[];\n  endpoint: ChatAttachmentWorkspaceEndpoint;\n  sessionId: string;\n  workspaceRoot: string;\n  createId?: () => string;\n}): Promise<Array<TextPartInput | FilePartInput>> {\n  if (input.attachments.length === 0) return [];\n\n  const workspaceRoot = input.workspaceRoot.trim();\n  if (!workspaceRoot) {\n    throw new Error(\"Workspace path is unavailable; attachments could not be copied for tool access.\");\n  }\n\n  const workspaceId = input.endpoint.workspaceId.trim();\n  if (!workspaceId) {\n    throw new Error(\"Workspace endpoint is unavailable; attachments could not be copied for tool access.\");\n  }\n\n  const uploaded: UploadedChatAttachment[] = [];\n  for (const attachment of input.attachments) {\n    // Oversized images are re-encoded here, at send time, so the composer chip\n    // appears instantly at attach time and the canvas work happens while the\n    // chip already shows its uploading state. When the transport uploads the\n    // original file from its local path, re-encoding would detach that path,\n    // so the original bytes are sent instead.\n    const file = input.endpoint.client.uploadInboxPrefersOriginalFile?.(attachment.file)\n      ? attachment.file\n      : await compressImageFile(attachment.file);\n    const metadata = resolveAttachmentFileMetadata(file);","sourceCodeStart":329,"sourceCodeEnd":365,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/apps/app/src/react-app/domains/session/sync/attachment-file-part.ts#L329-L365","documentation":"composerAttachmentsToWorkspaceFileParts copies composer attachments into the worker workspace so tools can access them, which requires an absolute workspace root path. When input.workspaceRoot is missing or whitespace-only, it throws this error before copying any files.","triggerScenarios":"Sending a message with attachments while workspaceRoot is '' or only whitespace — typically the workspace root has not resolved yet or the workspace/session was created without a root directory.","commonSituations":"Attaching files before the workspace finishes initializing; a workspace configured without a root directory; a race where send is triggered during workspace switch.","solutions":["Gate the send/attach flow on a resolved, non-empty workspaceRoot.","Wait for workspace initialization (root selection) before allowing attachments.","Catch the error and prompt the user to select/open a workspace folder."],"exampleFix":"// before: await composerAttachmentsToWorkspaceFileParts({ attachments, workspaceRoot: root, ... }) | // after: if (!root.trim()) throw new Error('Select a workspace folder first'); await composerAttachmentsToWorkspaceFileParts({ attachments, workspaceRoot: root, ... })","handlingStrategy":"validation","validationCode":"if (!workspaceRoot || !workspaceRoot.trim()) { showToast('Select a workspace folder before attaching files'); return; } await composerAttachmentsToWorkspaceFileParts({ attachments, workspaceRoot, endpoint, sessionId });","typeGuard":"function hasWorkspaceRoot(root: string | undefined | null): root is string { return typeof root === 'string' && root.trim().length > 0; }","tryCatchPattern":"try { await composerAttachmentsToWorkspaceFileParts({ attachments, workspaceRoot, endpoint, sessionId }); } catch (e) { if (String(e.message).includes('Workspace path is unavailable')) { promptWorkspaceSelection(); } else { throw e; } }","preventionTips":["Block the composer send/attach until a workspace root is resolved.","Revalidate the root after workspace switches or session restores.","Handle the workspace-initializing state explicitly in the UI."],"tags":["attachments","workspace","path","precondition"],"backgroundTag":"missing-workspace-root","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}