← Back to blog
by rn00m

PDF iFrame not showing in production


Problem

Last Friday, while working on my Kanji Sensei App I encountered an issue where my PDF ( pdf-lib) preview iFrame worked perfectly on localhost, but completely failed in production.

In Chrome devtools I did observe, see below code block, and at first thought I suspected it be some CSP issue, but that wasn’t the case.

Uncaught (in promise) TypeError: Cannot read properties of null (reading 'style')
at Gu (kanji-sensei.astro_astro_type_script_index_0_lang.C-pL7it-.js:58:2649)
at kanji-sensei.astro_astro_type_script_index_0_lang.C-pL7it-.js:58:2719

Troubleshooting

I kept staring at my click handler, but I could not see the issue what was wrong. Convinced something was wrong there and yet still in doubt. For sanity, I even asked AI to double‑check it and everything looked fine.

Below the relevant part:

      // 3. Click Handler
      let currentPdfUrl = null;

      btn.addEventListener("click", async () => {
        const data = window.currentKanji;
        if (!data) return;

        // 3.1 Generate PDF bytes
        const pdfBytes = await generateKanjiPDF(data);
        const blob = new Blob([pdfBytes], { type: "application/pdf" });

        // 3.2 Clean up previous URL to prevent memory leaks
        if (currentPdfUrl) URL.revokeObjectURL(currentPdfUrl);
        currentPdfUrl = URL.createObjectURL(blob);

        // 3.3 Inject the iframe in container
        const container = document.getElementById("pdf-container");
        if (container) {
          container.innerHTML = `
    <iframe
      id="pdf-preview"
      src="${currentPdfUrl}"
      style="display: block; width: 100%; height: 500px;"
      class="mt-4 border rounded">
    </iframe>`;

          setTimeout(() => {
            const preview = document.getElementById("pdf-preview");
            preview?.scrollIntoView({ behavior: "smooth" });
          }, 0);
        }

        // 4. Trigger the download
        const link = document.createElement("a");
        link.href = currentPdfUrl;
        link.download = `${data.kanji}-practice.pdf`;
        link.click();
      });

Everything looked correct, yet still no preview in production I still could not find it and started playing with my mousewheel, up and down, up and down. While scrolling up and down the page, I suddenly remembered something……I deactivated iFrame to show up on mobile.

Culprit

      if (!isMobile) {
        const preview = document.getElementById("pdf-preview");
          preview.style.display = "block";
          preview.src = currentPdfUrl;
          preview.scrollIntoView({ behavior: "smooth" });
      } else {
        // Optioneel: Aangezien geen preview op mobiel, een kleine toast
        console.log("Mobile detected: skipping preview, starting download.");
      }

In production, due to timing differences, the iframe did not exist yet when this code ran, which explains:

Uncaught (in promise) TypeError: Cannot read properties of null (reading 'style')

Solution

Simply guard against NULL:

if (preview) {}

like so:

      if (!isMobile) {
        const preview = document.getElementById("pdf-preview");
        if (preview) {
          preview.style.display = "block";
          preview.src = currentPdfUrl;
          preview.scrollIntoView({ behavior: "smooth" });
        }
      } else {
        // Optioneel: Aangezien geen preview op mobiel, een kleine toast
        console.log("Mobile detected: skipping preview, starting download.");
      }

After the implementation…it worked in production!

Lesson Learned

  • Production behaves differently from localhost, especially with DOM timing.
  • Never assume an element exists just because it “always did” during development.
  • Features disabled for mobile can quietly affect desktop logic if you forget they’re there.
  • A simple if (element) guard can prevent runtime errors that only appear in optimized builds.
  • Error messages are usually telling the truth, if it says null, it’s probably null.