danny-avila/LibreChat · error

Invalid input type. Expected URL, Buffer, or File.

Error message

Invalid input type. Expected URL, Buffer, or File.

What it means

Thrown by the input-type dispatch in the avatar uploader when `input` is none of: string (treated as URL), Buffer (raw bytes), or a File object (with a `.path`). This is the fallback else-branch after all three supported input shapes are checked. It prevents passing arbitrary objects (e.g., a plain object, a number, a ReadStream) into sharp(), which would produce a confusing downstream error.

Source

Thrown at api/server/services/Files/images/avatar.js:107

 * @throws {Error} Throws an error if the user ID is undefined, the input type is invalid, the image fetching fails,
 *                 or any other error occurs during the processing.
 */
async function resizeAvatar({ userId, input, desiredFormat = EImageOutputType.PNG, fetchOptions }) {
  try {
    if (userId === undefined) {
      throw new Error('User ID is undefined');
    }

    let imageBuffer;
    if (typeof input === 'string') {
      imageBuffer = await fetchAvatarBuffer(input, fetchOptions);
    } else if (input instanceof Buffer) {
      imageBuffer = input;
    } else if (typeof input === 'object' && input instanceof File) {
      const fileContent = await fs.readFile(input.path);
      imageBuffer = Buffer.from(fileContent);
    } else {
      throw new Error('Invalid input type. Expected URL, Buffer, or File.');
    }

    const metadata = await sharp(imageBuffer).metadata();
    const { width, height } = metadata;
    const minSize = Math.min(width, height);

    if (metadata.format === 'gif') {
      const resizedBuffer = await sharp(imageBuffer, { animated: true })
        .extract({
          left: Math.floor((width - minSize) / 2),
          top: Math.floor((height - minSize) / 2),
          width: minSize,
          height: minSize,
        })
        .resize(250, 250)
        .gif()
        .toBuffer();

View on GitHub (pinned to 5ff282f900)

Solutions

  1. Ensure `input` is one of: a URL string, a Node Buffer, or an Express/Multer File object.
  2. Convert browser `Uint8Array`/`ArrayBuffer` via `Buffer.from(uint8)` before calling.
  3. For form uploads, route through the request's `req.file` (Multer) so a File object is passed.
  4. Add a TypeScript discriminated union on the input parameter to catch mismatches at compile time.

Example fix

// before
await uploadAvatar({ userId, input: { data: bytes } });

// after
await uploadAvatar({ userId, input: Buffer.from(bytes) });
Defensive patterns

Strategy: type-guard

Type guard

/** @param {unknown} i */
function isValidAvatarInput(i) {
  if (typeof i === 'string') return true;
  if (Buffer.isBuffer(i)) return true;
  return typeof i === 'object' && i !== null && 'path' in i && typeof i.path === 'string';
}

Try / catch

try { await uploadAvatar({ userId, input }); }
catch (e) {
  if (/Invalid input type/.test(e.message)) return res.status(400).json({ error: 'Avatar must be a URL, Buffer, or File.' });
  throw e;
}

Prevention

When it happens

Trigger: Calling uploadAvatar with `input` that is a plain object, number, boolean, ReadStream, ArrayBuffer, Uint8Array (not a Buffer), or a front-end FormData value that wasn't materialized into a File. Also passing `null` or `undefined` after a preceding check expects a different shape.

Common situations: Frontend sending a JSON-serialized blob instead of multipart FormData; an integration passing a `Uint8Array` from a browser API instead of converting to Buffer; misrouted call where the caller assumed uploadAvatar accepts a ReadStream.

Related errors


AI-assisted analysis of danny-avila/LibreChat@5ff282f900 (2026-08-12). Data as JSON: /api/errors/045575f369824c41. Report an issue: GitHub.