different-ai/openwork · error

Workspace path is unavailable; attachments could not be copi

Error message

Workspace path is unavailable; attachments could not be copied for tool access.

What it means

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.

Source

Thrown at apps/app/src/react-app/domains/session/sync/attachment-file-part.ts:347

    type: "file",
    url: item.url,
    filename: item.filename,
    mime: modelMime,
  };
}

export async function composerAttachmentsToWorkspaceFileParts(input: {
  attachments: ComposerAttachment[];
  endpoint: ChatAttachmentWorkspaceEndpoint;
  sessionId: string;
  workspaceRoot: string;
  createId?: () => string;
}): Promise<Array<TextPartInput | FilePartInput>> {
  if (input.attachments.length === 0) return [];

  const workspaceRoot = input.workspaceRoot.trim();
  if (!workspaceRoot) {
    throw new Error("Workspace path is unavailable; attachments could not be copied for tool access.");
  }

  const workspaceId = input.endpoint.workspaceId.trim();
  if (!workspaceId) {
    throw new Error("Workspace endpoint is unavailable; attachments could not be copied for tool access.");
  }

  const uploaded: UploadedChatAttachment[] = [];
  for (const attachment of input.attachments) {
    // Oversized images are re-encoded here, at send time, so the composer chip
    // appears instantly at attach time and the canvas work happens while the
    // chip already shows its uploading state. When the transport uploads the
    // original file from its local path, re-encoding would detach that path,
    // so the original bytes are sent instead.
    const file = input.endpoint.client.uploadInboxPrefersOriginalFile?.(attachment.file)
      ? attachment.file
      : await compressImageFile(attachment.file);
    const metadata = resolveAttachmentFileMetadata(file);

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Gate the send/attach flow on a resolved, non-empty workspaceRoot.
  2. Wait for workspace initialization (root selection) before allowing attachments.
  3. Catch the error and prompt the user to select/open a workspace folder.

Example fix

// before: await composerAttachmentsToWorkspaceFileParts({ attachments, workspaceRoot: root, ... }) | // after: if (!root.trim()) throw new Error('Select a workspace folder first'); await composerAttachmentsToWorkspaceFileParts({ attachments, workspaceRoot: root, ... })
Defensive patterns

Strategy: validation

Validate before calling

if (!workspaceRoot || !workspaceRoot.trim()) { showToast('Select a workspace folder before attaching files'); return; } await composerAttachmentsToWorkspaceFileParts({ attachments, workspaceRoot, endpoint, sessionId });

Type guard

function hasWorkspaceRoot(root: string | undefined | null): root is string { return typeof root === 'string' && root.trim().length > 0; }

Try / catch

try { await composerAttachmentsToWorkspaceFileParts({ attachments, workspaceRoot, endpoint, sessionId }); } catch (e) { if (String(e.message).includes('Workspace path is unavailable')) { promptWorkspaceSelection(); } else { throw e; } }

Prevention

When it happens

Trigger: 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.

Common situations: Attaching files before the workspace finishes initializing; a workspace configured without a root directory; a race where send is triggered during workspace switch.

Related errors


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/b037d0f25297336f. Report an issue: GitHub.