{"record":{"id":"c103b34e7b77a4d7","repo":"different-ai/openwork","slug":"workspace-export-is-only-supported-for-local-works","errorCode":null,"errorMessage":"Workspace export is only supported for local workspaces","messagePattern":"Workspace export is only supported for local workspaces","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/desktop/electron/workspace-archive.mjs","lineNumber":258,"sourceCode":"  return !normalized.split(\"/\").some((part) => part === \"..\" || part === \"\");\n}\n\nfunction defaultOpenworkConfig(targetDir, preset = \"starter\") {\n  return {\n    version: 1,\n    workspace: {\n      name: path.basename(targetDir) || \"Workspace\",\n      createdAt: nowMs(),\n      preset,\n    },\n    authorizedRoots: [targetDir],\n    reload: null,\n  };\n}\n\nexport async function exportWorkspaceConfig({ workspace, outputPath }) {\n  if (!workspace?.path || workspace.workspaceType === \"remote\") {\n    throw new Error(\"Workspace export is only supported for local workspaces\");\n  }\n  const workspaceRoot = workspace.path;\n  if (!(await pathExists(workspaceRoot))) {\n    throw new Error(`Workspace path not found: ${workspaceRoot}`);\n  }\n\n  const { entries, excluded } = await collectWorkspaceEntries(workspaceRoot);\n  if (entries.length === 0) throw new Error(\"No workspace config files found to export\");\n\n  const files = [];\n  const included = [];\n  for (const entry of entries) {\n    files.push({ name: entry.rel, data: await readFile(entry.absolute) });\n    included.push(entry.rel);\n  }\n  files.push({\n    name: \"manifest.json\",\n    data: `${JSON.stringify({","sourceCodeStart":240,"sourceCodeEnd":276,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/apps/desktop/electron/workspace-archive.mjs#L240-L276","documentation":"exportWorkspaceConfig packages a workspace's local config (opencode.json and .opencode/) into a ZIP. It only supports local workspaces: if the workspace object has no path, or its workspaceType is 'remote', exporting is refused because there is no local filesystem tree to archive.","triggerScenarios":"Calling exportWorkspaceConfig with workspace.workspaceType === 'remote', or with a workspace object missing the path property (null/undefined path).","commonSituations":"Selecting a cloud/remote workspace in the UI and attempting an export; passing a partially-constructed workspace object without path; version changes where workspaceType was added and older callers omit it with no path.","solutions":["Call exportWorkspaceConfig only for workspaces whose workspaceType is 'local' and which have a valid path","For remote workspaces, clone/checkout the content locally first, then export that directory","Ensure the workspace object is fully loaded (path populated) before exporting"],"exampleFix":"// before\nawait exportWorkspaceConfig({ workspace: { id: 'remote-1', workspaceType: 'remote' } })\n// after\nif (ws.workspaceType !== 'remote' && ws.path) {\n  await exportWorkspaceConfig({ workspace: ws })\n}","handlingStrategy":"type-guard","validationCode":"function canExport(ws) {\n  return Boolean(ws?.path) && ws.workspaceType !== 'remote';\n}","typeGuard":"function isExportableWorkspace(ws) {\n  return typeof ws?.path === 'string' && ws.path.length > 0 && ws.workspaceType !== 'remote';\n}","tryCatchPattern":"try {\n  await exportWorkspaceConfig({ workspace });\n} catch (err) {\n  if (err.message === 'Workspace export is only supported for local workspaces') {\n    // surface 'choose a local workspace' to the user\n  } else throw err;\n}","preventionTips":["Check workspaceType in the UI before offering Export","Ensure workspace objects are fully loaded (path populated)","Handle remote workspaces with a separate flow"],"tags":["workspace","validation","unsupported-operation"],"backgroundTag":"unsupported-workspace-type","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}