Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Start with the value passed to doc.addImage(). In most React applications, the error means that value is empty, is not an image, has a malformed data-URL header, is being read before an asynchronous conversion finishes, or cannot be identified as the format you intended. Inspect the runtime value, wait for the image to load, and pass the format explicitly when detection is uncertain.

What the error actually means

jsPDF’s addImage method accepts several image representations: a Base64 data URL string, an HTMLImageElement, an HTMLCanvasElement, a Uint8Array, and RGBA pixel data. The message “Supplied Data is not a valid base64-String” is therefore a symptom, not a diagnosis. A value can be Base64-encoded and still contain a PDF, JSON document, error page, or unsupported image rather than image bytes.

The same applies to “AddImage does not support files of type ‘UNKNOWN’.” jsPDF may not recognize the type from the supplied value. Check the actual value and the jsPDF version installed in your project before changing code.

Use this debugging sequence first

  1. Inspect the value immediately before the call. Log its JavaScript type and a short prefix, not the complete image.
  2. Validate a data URL. It should look like data:image/png;base64,... or another supported image MIME type, contain the exact ;base64, separator, and have a nonempty payload.
  3. Check asynchronous timing. A FileReader, image element, fetch, or canvas operation must finish before addImage runs.
  4. Check the bytes. Make sure the content is an image, not an API error response, HTML page, PDF, or undefined converted to a string.
  5. Use an explicit format when needed. Pass PNG, JPEG, or WEBP matching the real data.
  6. Compare with the API for your installed release. Implementation details can differ between releases; evidence from jsPDF 2.5.1 should not automatically be applied to another version.

Validate the value without flooding your console

function inspectImageData(value) {
  console.log({
    type: typeof value,
    isString: typeof value === "string",
    prefix: typeof value === "string" ? value.slice(0, 40) : undefined,
    length: typeof value === "string" ? value.length : undefined
  });
}

function assertImageDataUrl(value) {
  if (typeof value !== "string") {
    throw new TypeError("Expected an image data URL string");
  }

  const match = value.match(/^data:(image/[a-z0-9.+-]+);base64,(.+)$/i);
  if (!match || match[2].trim() === "") {
    throw new Error("Expected data:image/...;base64,");
  }

  return value;
}

This check confirms the shape of a data URL, but it does not prove that the decoded bytes are a valid image. A syntactically correct payload can still represent the wrong file.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Fix the common React FileReader race

FileReader.readAsDataURL() completes asynchronously. Do not call addImage immediately after starting the read, and do not assume a state variable has the new value during the same event handler. Resolve the read first, then create the PDF.

import { jsPDF } from "jspdf";

function readAsDataURL(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result);
    reader.onerror = () => reject(reader.error);
    reader.readAsDataURL(file);
  });
}

async function addUploadedImageToPdf(file) {
  if (!file || !file.type.startsWith("image/")) {
    throw new Error("Choose an image file");
  }

  const imageData = await readAsDataURL(file);
  assertImageDataUrl(imageData);

  const doc = new jsPDF();
  doc.addImage(imageData, "PNG", 10, 10, 100, 60);
  doc.save("image.pdf");
}

The PNG argument is only correct when the selected file really is PNG. For a JPEG or WebP file, pass the matching format. You can retain the original MIME type and map it to the format name:

function jsPdfFormatFromMime(mime) {
  const formats = {
    "image/png": "PNG",
    "image/jpeg": "JPEG",
    "image/webp": "WEBP"
  };
  const format = formats[mime.toLowerCase()];
  if (!format) throw new Error(`Unsupported image type: ${mime}`);
  return format;
}

async function makePdf(file) {
  const dataUrl = await readAsDataURL(file);
  assertImageDataUrl(dataUrl);
  const doc = new jsPDF();
  doc.addImage(dataUrl, jsPdfFormatFromMime(file.type), 10, 10, 100, 60);
  doc.save("image.pdf");
}

Do not add a second data-URL prefix

A complete data URL already includes its MIME header and separator. This is wrong:

const broken = "data:image/png;base64," + completeDataUrl;

If your source is a raw Base64 payload, add one correct header. If it is already a data URL, pass it unchanged:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
function toPngDataUrl(value) {
  if (typeof value !== "string") throw new TypeError("Expected a string");
  return value.startsWith("data:")
    ? value
    : `data:image/png;base64,${value}`;
}

Only use that helper when you have independently established that a headerless value contains PNG bytes. Do not label arbitrary text as PNG.

Use image and canvas inputs when they are what you already have

Base64 is not required. A loaded image element or canvas can be passed directly, and binary workflows can use a Uint8Array or RGBA data. Waiting for the source to load is still essential:

function loadImage(src) {
  return new Promise((resolve, reject) => {
    const image = new Image();
    image.onload = () => resolve(image);
    image.onerror = () => reject(new Error("Image failed to load"));
    image.src = src;
  });
}

async function pdfFromImageUrl(url) {
  const image = await loadImage(url);
  const doc = new jsPDF();
  doc.addImage(image, "JPEG", 10, 10, 100, 60);
  doc.save("image.pdf");
}

For canvas content, call addImage after drawing is complete and specify the actual output format if recognition is not reliable:

const canvas = document.querySelector("canvas");
const doc = new jsPDF();
doc.addImage(canvas, "PNG", 10, 10, 100, 60);
doc.save("canvas.pdf");

React-specific failure modes

State is still empty

If a file-reading callback calls setImageData(result), a separate click handler can run before the state update is available. Keep the value in the same asynchronous flow, or trigger PDF creation from an effect that verifies the state is a nonempty data URL.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The component unmounted

Cancel or ignore a pending read when a component unmounts, especially when users can select several files quickly. Otherwise an old result can overwrite the current selection.

Remote images fail because of browser security

An image loaded from another origin may be displayed but cannot necessarily be exported to a canvas. Configure the server’s CORS response and set the image’s cross-origin behavior before assigning its source, or obtain the bytes through a permitted server-side path.

The URL returned an error page

A fetch can succeed at the HTTP level while returning HTML or JSON. Check the response status and content type before converting the body. Passing an error response as an image produces misleading Base64 or unknown-format errors.

Common errors and precise fixes

Symptom Likely cause Fix
“Supplied Data is not a valid base64-String” Empty, truncated, malformed, or non-image string Inspect the prefix and length, validate the data URL, and verify the decoded bytes are an image.
“files of type ‘UNKNOWN’” Format detection failed Pass the correct explicit format such as PNG, JPEG, or WEBP.
Works only sometimes Read or image load is still pending Await the FileReader promise or image onload event before creating the PDF.
Blank or damaged output Wrong dimensions, incomplete source, or incorrect format label Wait for loading, use dimensions appropriate to the source, and match the format to the bytes.
Prefix appears twice Header added to an already complete data URL Pass the existing data URL unchanged, or add one header only to a raw payload.
Failure after a dependency update Version-specific behavior or changed call signature Check the installed jsPDF version and its matching documentation and lockfile.

Security and dependency note

If untrusted users control image URLs or image data, review the jsPDF security advisory before deploying. The advisory published on 2025-03-18 identifies versions through 3.0.0 as affected by a regular-expression denial-of-service issue and lists 3.0.1 or later as patched for that advisory. This is separate from diagnosing invalid Base64; verify the version pinned by your application and follow the current project guidance.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Performance, reliability, and cost considerations

  • Base64 increases the in-memory representation of binary data, so very large images can cause browser memory pressure. Resize images before embedding when print resolution permits.
  • Load once and reuse the resulting image or canvas if several pages need the same asset.
  • Keep user-visible errors specific: distinguish “file read failed,” “unsupported image type,” and “PDF generation failed.”
  • Do not log complete data URLs in production; they may contain sensitive user content and can overwhelm observability systems.
  • Pin and update jsPDF deliberately. Re-test image inputs after upgrades because the cited implementation evidence is version-specific.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your goal is to obtain a clean image of a web page rather than embed a user-uploaded image in a PDF, ScreenshotNeo provides a single screenshot API request. Its cleanup step accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers. It also offers an MCP server for Claude, Cursor, and other MCP clients.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for the full option set, including full-page and element captures, device and retina settings, PDFs, custom CSS and JavaScript, request blocking, cookies and headers, caching, signed links, asynchronous webhooks, bulk capture, and usage reporting. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Sign up for the free plan.

FAQ

Can I pass only the Base64 characters to addImage?

Use a correctly typed data URL or another supported input. A headerless payload is easy to mislabel, so confirm its real image format before adding a header or supplying the format argument.

Does a valid data URL guarantee that jsPDF can embed it?

No. The syntax can be correct while the payload is not an image or is an image format unsupported by the installed implementation.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Should every image be labeled PNG?

No. The explicit format must match the actual bytes. Use JPEG or WEBP when those are the source formats, and use PNG only for PNG data.

Frequently Asked Questions

Can I pass only the Base64 characters to addImage?

Use a correctly typed data URL or another supported input. A headerless payload is easy to mislabel, so confirm its real image format before adding a header or supplying the format argument.

Does a valid data URL guarantee that jsPDF can embed it?

No. The syntax can be correct while the payload is not an image or is an image format unsupported by the installed implementation.

Should every image be labeled PNG?

No. The explicit format must match the actual bytes. Use JPEG or WEBP when those are the source formats, and use PNG only for PNG data.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.