{"record":{"id":"368ff6a64d2f6fd7","repo":"payloadcms/payload","slug":"expected-response-from-the-upload-handler","errorCode":null,"errorMessage":"Expected response from the upload handler.","messagePattern":"Expected response from the upload handler\\.","errorType":"http","errorClass":"APIError","httpStatus":500,"severity":"error","filePath":"packages/payload/src/uploads/getFileFromUploadInstructions.ts","lineNumber":72,"sourceCode":"        /**\n         * - If a handler returns a Response, the response will be sent to the client and no further handlers will be run.\n         * - If a handler returns null, the next handler will be run.\n         *\n         * @see packages/payload/src/uploads/types.ts\n         */\n        break\n      }\n    } catch (err) {\n      error = err\n    }\n  }\n\n  if (!response) {\n    if (error) {\n      req.payload.logger.error(error)\n    }\n\n    throw new APIError('Expected response from the upload handler.')\n  }\n\n  if (response.status >= 300 && response.status < 400) {\n    const redirectUrl = response.headers.get('Location')\n    if (redirectUrl) {\n      response = await fetch(redirectUrl)\n    }\n  }\n\n  return {\n    name: file.filename,\n    data: Buffer.from(await response.arrayBuffer()),\n    mimetype: response.headers.get('Content-Type') || file.mimeType,\n    size: file.size,\n    uploadReference: file.uploadReference,\n  }\n}\n","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/payload/src/uploads/getFileFromUploadInstructions.ts#L54-L90","documentation":"When resolving an adapter-style upload reference, Payload iterates `uploadConfig.handlers`; each handler may return a `Response` (success → loop breaks) or `null` (try next). If **all** handlers return null/falsy (or threw and were swallowed into the `error` variable), the function logs the last handler error (if any) and throws `APIError` (default HTTP 500) `Expected response from the upload handler.`","triggerScenarios":"`getFileFromUploadInstructions` with an adapter reference where every handler in `uploadConfig.handlers` returns `null`/void/undefined, or each throws an exception caught by the per-handler `try/catch`. The last captured error is logged, but the surfaced message is generic.","commonSituations":"A storage adapter handler cannot locate the object (key mismatch, deleted blob) and returns null instead of throwing. The adapter credentials are wrong and the handler silently fails. A custom handler has a bug causing it to resolve undefined. The upload reference points to an object the handler cannot fetch (wrong bucket, region).","solutions":["Check the Payload server logs for the captured handler `error` — it carries the real cause.","Verify the storage adapter credentials/region/bucket match the upload reference.","Ensure the adapter's handler returns a `Response` for valid references and throws (not returns null) for genuine errors so they surface.","Confirm the `uploadReference` produced by `/upload-instructions` matches what the handler expects (key, prefix, region).","Update the adapter plugin — older handlers were more likely to swallow errors."],"exampleFix":"// before — custom handler swallows errors and returns null\nhandlers: [async (req, args) => {\n  try { return await fetchFromMyStore(args.params.uploadReference) }\n  catch { return null }\n}]\n\n// after — let errors propagate so they are logged and surfaced\nhandlers: [async (req, args) => {\n  return await fetchFromMyStore(args.params.uploadReference) // throws on failure\n}]","handlingStrategy":"try-catch","validationCode":"async function handlerReturnsResponse(handler: (req: any, args: any) => unknown, args: any): Promise<boolean> {\n  try {\n    const r = await handler({} as any, args)\n    return r instanceof Response\n  } catch {\n    return false\n  }\n}\n\nconst handlers = collection.upload?.handlers ?? []\nif (!handlers.some((h) => typeof h === 'function')) {\n  throw new Error('No upload handler will produce a Response')\n}","typeGuard":"import { APIError } from 'payload'\nfunction isExpectedResponseError(err: unknown): err is InstanceType<typeof APIError> {\n  return err instanceof Error && /expected response from the upload handler/i.test(err.message)\n}","tryCatchPattern":"try {\n  await payload.create({ collection: 'media', data, file })\n} catch (err) {\n  if (isExpectedResponseError(err)) {\n    // check payload.logger output for the captured handler error\n    // verify adapter credentials/region/bucket and that the reference is valid\n  } else throw err\n}","preventionTips":["Ensure adapter handlers return a `Response` for valid references and throw on error (not return null).","Verify storage credentials, region, and bucket match the upload reference.","Keep the adapter plugin up to date."],"tags":["upload","storage-adapter","handlers","error-handling"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}