payloadcms/payload · error · APIError

Expected response from the upload handler.

Error message

Expected response from the upload handler.

What it means

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.`

Source

Thrown at packages/payload/src/uploads/getFileFromUploadInstructions.ts:72

        /**
         * - If a handler returns a Response, the response will be sent to the client and no further handlers will be run.
         * - If a handler returns null, the next handler will be run.
         *
         * @see packages/payload/src/uploads/types.ts
         */
        break
      }
    } catch (err) {
      error = err
    }
  }

  if (!response) {
    if (error) {
      req.payload.logger.error(error)
    }

    throw new APIError('Expected response from the upload handler.')
  }

  if (response.status >= 300 && response.status < 400) {
    const redirectUrl = response.headers.get('Location')
    if (redirectUrl) {
      response = await fetch(redirectUrl)
    }
  }

  return {
    name: file.filename,
    data: Buffer.from(await response.arrayBuffer()),
    mimetype: response.headers.get('Content-Type') || file.mimeType,
    size: file.size,
    uploadReference: file.uploadReference,
  }
}

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Check the Payload server logs for the captured handler `error` — it carries the real cause.
  2. Verify the storage adapter credentials/region/bucket match the upload reference.
  3. Ensure the adapter's handler returns a `Response` for valid references and throws (not returns null) for genuine errors so they surface.
  4. Confirm the `uploadReference` produced by `/upload-instructions` matches what the handler expects (key, prefix, region).
  5. Update the adapter plugin — older handlers were more likely to swallow errors.

Example fix

// before — custom handler swallows errors and returns null
handlers: [async (req, args) => {
  try { return await fetchFromMyStore(args.params.uploadReference) }
  catch { return null }
}]

// after — let errors propagate so they are logged and surfaced
handlers: [async (req, args) => {
  return await fetchFromMyStore(args.params.uploadReference) // throws on failure
}]
Defensive patterns

Strategy: try-catch

Validate before calling

async function handlerReturnsResponse(handler: (req: any, args: any) => unknown, args: any): Promise<boolean> {
  try {
    const r = await handler({} as any, args)
    return r instanceof Response
  } catch {
    return false
  }
}

const handlers = collection.upload?.handlers ?? []
if (!handlers.some((h) => typeof h === 'function')) {
  throw new Error('No upload handler will produce a Response')
}

Type guard

import { APIError } from 'payload'
function isExpectedResponseError(err: unknown): err is InstanceType<typeof APIError> {
  return err instanceof Error && /expected response from the upload handler/i.test(err.message)
}

Try / catch

try {
  await payload.create({ collection: 'media', data, file })
} catch (err) {
  if (isExpectedResponseError(err)) {
    // check payload.logger output for the captured handler error
    // verify adapter credentials/region/bucket and that the reference is valid
  } else throw err
}

Prevention

When it happens

Trigger: `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.

Common situations: 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).

Related errors


AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12). Data as JSON: /api/errors/368ff6a64d2f6fd7. Report an issue: GitHub.