{"record":{"id":"d59fdfe7c692065a","repo":"paperclipai/paperclip","slug":"unsupported-createos-transfer-kind","errorCode":null,"errorMessage":"Unsupported CreateOS transfer kind.","messagePattern":"Unsupported CreateOS transfer kind\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/plugins/sandbox-providers/createos/src/file-sync.ts","lineNumber":94,"sourceCode":"      const init: RequestInit & { duplex: \"half\" } = {\n        method: \"PUT\", body: Readable.toWeb(source) as ReadableStream<Uint8Array>,\n        duplex: \"half\", headers: { \"Content-Type\": \"application/octet-stream\" }, signal,\n      };\n      const response = await client.request(`/sandboxes/${id}/files?path=${encodeURIComponent(remote)}`, init);\n      await response.body?.cancel();\n    } finally { source.destroy(); }\n  };\n  const download = async (remote: string, local: string, mode = 0o600) => {\n    const response = await client.request(`/sandboxes/${id}/files?path=${encodeURIComponent(remote)}`, { signal });\n    if (!response.body) throw new Error(\"CreateOS file download has no body.\");\n    await pipeline(response.body, createWriteStream(local, { flags: \"wx\", mode }), { signal });\n  };\n\n  // Validate every mapping before beginning side effects. Host paths are\n  // orchestrator-authored and checked by its source/target-root guard.\n  for (const operation of params.operations) {\n    for (const mapping of operation.files) {\n      if (![\"file\", \"directory\"].includes(mapping.kind)) throw new Error(\"Unsupported CreateOS transfer kind.\");\n      if (!path.isAbsolute(direction === \"in\" ? mapping.sourcePath : mapping.targetPath)) throw new Error(\"CreateOS transfer requires an absolute host path.\");\n      if (mapping.mode != null && (!Number.isInteger(mapping.mode) || mapping.mode < 0 || mapping.mode > 0o777)) throw new Error(\"Invalid CreateOS file mode.\");\n      assertRemotePath(direction === \"in\" ? mapping.targetPath : mapping.sourcePath);\n    }\n    for (const command of operation.postUploadCommands ?? []) {\n      assertRemotePath(command.cwd ?? ROOT);\n      if (command.timeoutMs != null && (!Number.isInteger(command.timeoutMs) || command.timeoutMs < 1 || command.timeoutMs > 86_400_000)) throw new Error(\"Invalid CreateOS transfer timeout.\");\n    }\n    if (direction === \"out\" && operation.postUploadCommands?.length) throw new Error(\"Outbound CreateOS transfers cannot run post-upload commands.\");\n  }\n\n  for (const operation of params.operations) {\n    let bytesTransferred = 0;\n    let filesTransferred = 0;\n    for (const mapping of operation.files) {\n      signal.throwIfAborted();\n      const local = direction === \"in\" ? mapping.sourcePath : mapping.targetPath;\n      const remote = direction === \"in\" ? mapping.targetPath : mapping.sourcePath;","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/packages/plugins/sandbox-providers/createos/src/file-sync.ts#L76-L112","documentation":"syncFiles validates every file mapping's `kind` before performing any side effects. Only \"file\" and \"directory\" transfers are supported by the CreateOS provider; any other kind value fails fast with this error. It is a pre-flight guard so an unsupported transfer never partially executes.","triggerScenarios":"An operation in params.operations contains a file mapping whose `kind` is not exactly \"file\" or \"directory\" (e.g. \"symlink\", a typo like \"dir\", or an undefined kind from a malformed operation object).","commonSituations":"Orchestrator or caller code constructs mappings by hand with wrong literal strings; a schema change upstream introduces a new transfer kind before the CreateOS adapter supports it; JSON payloads with case differences (\"File\").","solutions":["Set mapping.kind to exactly \"file\" or \"directory\" for every mapping in the operation.","Validate operation payloads against the PluginEnvironmentSyncResult/params schema before calling syncFiles.","If you need symlink transfers, restructure them as file contents or add provider support — they are not supported today."],"exampleFix":"// before\n{ kind: \"dir\", sourcePath: \"/host/app\", targetPath: \"/work/app\" }\n// after\n{ kind: \"directory\", sourcePath: \"/host/app\", targetPath: \"/work/app\" }","handlingStrategy":"validation","validationCode":"const ok = ops.every(op => op.files.every(f => f.kind === \"file\" || f.kind === \"directory\"));\nif (!ok) throw new Error(\"mapping.kind must be 'file' or 'directory'\");","typeGuard":"const isTransferKind = (k: unknown): k is \"file\" | \"directory\" =>\n  k === \"file\" || k === \"directory\";","tryCatchPattern":null,"preventionTips":["Validate operations against the shared schema before calling syncFiles","Use string-literal types/consts instead of free-form strings for kind","Beware case differences from serialized JSON payloads"],"tags":["validation","file-transfer","invalid-enum-value"],"backgroundTag":"invalid-enum-value","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}