{"record":{"id":"7d9293dda3ae7a7c","repo":"paperclipai/paperclip","slug":"import-transfer-declaration-returned-no-data","errorCode":null,"errorMessage":"Import transfer declaration returned no data.","messagePattern":"Import transfer declaration returned no data\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"cli/src/commands/client/company.ts","lineNumber":1158,"sourceCode":"}\n\n/**\n * Declare (or resume) the transfer for these zip bytes and upload every part\n * the server reports missing, sequentially with per-part retries. Resolves\n * with the transfer id once the server holds every part.\n */\nexport async function uploadCompanyImportTransfer(\n  api: Pick<PaperclipApiClient, \"post\" | \"putRaw\">,\n  zipBytes: Uint8Array,\n  opts: { onProgress?: (progress: ImportTransferUploadProgress) => void } = {},\n): Promise<string> {\n  const manifest = buildImportTransferManifest(zipBytes);\n  const created = await api.post<CompanyImportTransferCreated>(\n    `/api/companies${COMPANY_IMPORT_TRANSFERS_ROUTE_PATH}`,\n    manifest,\n  );\n  if (!created) {\n    throw new Error(\"Import transfer declaration returned no data.\");\n  }\n  if (created.alreadyCompleted) {\n    // The server keys transfers by content, and this exact zip already\n    // finished an apply — its spooled parts are gone, so it cannot re-run.\n    throw new Error(\n      \"This exact package was already imported by a completed transfer. Re-export the package to import it again.\",\n    );\n  }\n  const missing = new Set(created.missingParts);\n  let uploadedParts = manifest.parts.length - missing.size;\n  let uploadedBytes = manifest.parts.reduce(\n    (sum, part) => (missing.has(part.index) ? sum : sum + part.byteSize),\n    0,\n  );\n  for (const part of manifest.parts) {\n    if (!missing.has(part.index)) continue;\n    const offset = part.index * manifest.partSizeBytes;\n    const bytes = zipBytes.subarray(offset, offset + part.byteSize);","sourceCodeStart":1140,"sourceCodeEnd":1176,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/cli/src/commands/client/company.ts#L1140-L1176","documentation":"Thrown by uploadCompanyImportTransfer when the POST to declare the transfer returns a falsy body. The server contract for /api/companies/.../imports/transfers requires a JSON object describing the transfer; an empty/204/null response means the API surface is broken or the client/server versions are out of sync.","triggerScenarios":"The PaperclipApiClient.post call resolves to undefined (e.g. a 204 No Content, a proxy that strips the body, a server bug returning empty, or a version mismatch where the route exists but the response shape changed). Network middleware that replaces the body with null.","commonSituations":"Talking to an older server that does not implement the chunked transfer endpoint. A reverse proxy or gateway swallowing the response body. A mock client in tests that forgets to return the created object. Client/server version skew after an upgrade.","solutions":["Verify the server is running a version that supports the imports/transfers route and returns the expected JSON.","Check the API base URL and any proxy in front of it is not stripping response bodies.","Update both server and CLI to compatible versions.","Inspect the raw HTTP response with curl against /api/companies/.../imports/transfers to confirm the server emits a body.","If this is a test double, ensure the mocked post returns a valid CompanyImportTransferCreated object."],"exampleFix":"// before (mock returns nothing)\nconst api = { post: async () => undefined, putRaw: async () => {} };\nawait uploadCompanyImportTransfer(api, zipBytes);\n// after\nconst created = { transferId: \"tfr_1\", missingParts: [0,1], alreadyCompleted: false };\nconst api = { post: async () => created, putRaw: async () => {} };\nawait uploadCompanyImportTransfer(api, zipBytes);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isValidTransferCreated(v: unknown): v is { transferId: string; missingParts: number[]; alreadyCompleted: boolean } {\n  return (\n    typeof v === \"object\" && v !== null &&\n    typeof (v as any).transferId === \"string\" &&\n    Array.isArray((v as any).missingParts) &&\n    typeof (v as any).alreadyCompleted === \"boolean\"\n  );\n}","tryCatchPattern":"try {\n  const transferId = await uploadCompanyImportTransfer(api, zipBytes);\n} catch (err) {\n  if (err instanceof Error && /returned no data/.test(err.message)) {\n    // server contract broken: surface to operator, check versions/proxy\n    throw new Error(`Import transfer endpoint returned empty body. Verify server version and proxy. Cause: ${err.message}`);\n  }\n  throw err;\n}","preventionTips":["Keep CLI and server versions in lockstep.","Smoke-test the transfers endpoint with curl after deploys.","In test doubles, always return a valid CompanyImportTransferCreated object.","Watch for proxies/gateways that strip response bodies."],"tags":["cli","api-contract","company-import","transfer","version-mismatch"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}