{"record":{"id":"ffd1df521dada12a","repo":"different-ai/openwork","slug":"failed-to-copy-attachment-metadata-filename-i-ffd1df","errorCode":null,"errorMessage":"Failed to copy attachment \"${metadata.filename}\" into this worker workspace: upload did not return a path","messagePattern":"Failed to copy attachment \"(.+?)\" into this worker workspace: upload did not return a path","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/app/src/react-app/domains/session/sync/attachment-file-part.ts","lineNumber":384,"sourceCode":"    const id = input.createId ? input.createId() : randomAttachmentId();\n    const inboxPath = buildChatAttachmentInboxPath({\n      sessionId: input.sessionId,\n      filename: metadata.filename,\n      id,\n    });\n\n    let result: InboxUploadResult;\n    try {\n      result = await input.endpoint.client.uploadInbox(workspaceId, file, { path: inboxPath });\n    } catch (error) {\n      throw new Error(uploadErrorMessage(metadata.filename, error));\n    }\n\n    if (result.ok === false) {\n      throw new Error(`Failed to copy attachment \"${metadata.filename}\" into this worker workspace: upload was rejected`);\n    }\n    if (!result.path.trim()) {\n      throw new Error(`Failed to copy attachment \"${metadata.filename}\" into this worker workspace: upload did not return a path`);\n    }\n    if (result.bytes !== file.size) {\n      throw new Error(`Failed to copy attachment \"${metadata.filename}\" into this worker workspace: expected ${file.size} bytes, wrote ${result.bytes}`);\n    }\n\n    const workspacePath = workspaceInboxPath(result.path);\n    const absolutePath = joinWorkspaceRelativePath(workspaceRoot, workspacePath);\n    uploaded.push({\n      filename: metadata.filename,\n      mime: metadata.mime,\n      bytes: result.bytes,\n      workspacePath,\n      url: toFileUrl(absolutePath),\n      file,\n    });\n  }\n\n  return [","sourceCodeStart":366,"sourceCodeEnd":402,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/apps/app/src/react-app/domains/session/sync/attachment-file-part.ts#L366-L402","documentation":"If uploadInbox reports success (result.ok !== false) but returns an empty/whitespace result.path, the client cannot reference the uploaded file, so it throws this error. This guards against a malformed success response where the stored file path is missing.","triggerScenarios":"Server returns a success envelope without a path — e.g. a server bug, a proxy stripping the response body field, or a protocol version mismatch where the path is under a different key.","commonSituations":"Running a newer client against an older server (or vice versa) that omits 'path'; custom server implementations of uploadInbox that forget to return the path.","solutions":["Fix or upgrade the server so uploadInbox always returns the stored inbox path on success.","Verify no proxy/middleware is dropping the path field from the response.","Retry the upload; if reproducible, log the raw response for a bug report."],"exampleFix":"// after uploadInbox resolves: if (!result.path?.trim()) { console.error('uploadInbox response missing path', result); } // report server bug","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function hasUploadPath(result: { ok?: boolean; path?: string }): result is { ok?: boolean; path: string } { return typeof result.path === 'string' && result.path.trim().length > 0; }","tryCatchPattern":"try { await composerAttachmentsToWorkspaceFileParts({ attachments, endpoint, sessionId, workspaceRoot }); } catch (e) { if (String(e.message).includes('upload did not return a path')) { reportServerBug(e); } else { throw e; } }","preventionTips":["Pin compatible client/server versions of the uploadInbox contract.","Ensure proxies/middleware do not strip response fields.","Add a server-side test asserting uploadInbox returns a non-empty path on success."],"tags":["upload","attachments","protocol","response-shape"],"backgroundTag":"missing-path-in-upload-response","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}