Troubleshooting
Common issues and how to resolve them
Below are solutions to the most frequently encountered issues when using CobaltPDF. If your problem isn't listed here, check the documentation or contact us at support@cobaltpdf.com or open an issue on GitHub.
Chromium requires several system libraries that are not installed by default in minimal Linux images or Docker containers.
Solution: Use the built-in cloud environment preset to configure the engine for your platform:
CobaltEngine.Configure(CloudEnvironment.ConfigureForDocker);
If you're building a custom Docker image, ensure these packages are installed:
RUN apt-get update && apt-get install -y \
libnss3 libatk1.0-0 libatk-bridge2.0-0 \
libcups2 libdrm2 libxkbcommon0 libxcomposite1 \
libxdamage1 libxrandr2 libgbm1 libpango-1.0-0 \
libcairo2 libasound2 libxshmfence1 fonts-liberation
For Azure App Service, use CloudEnvironment.ConfigureForAzure instead.
A blank or incomplete PDF usually means the page hadn't finished rendering when CobaltPDF captured it. This is common with JavaScript-heavy pages (React, Vue, Angular).
Solution: Use a wait strategy to delay capture until the page is ready:
// Wait for the network to be idle var pdf = await renderer .WithWaitStrategy(WaitOptions.DefaultNetworkIdle) .RenderUrlAsPdfAsync(url); // Or wait for a specific DOM element var pdf = await renderer .WithWaitStrategy(WaitOptions.ForSelector("#main-content")) .RenderUrlAsPdfAsync(url);
For SPAs, call window.cobaltNotifyRender() from your front-end code when the app is fully loaded, and use .WithWaitStrategy(WaitOptions.ForSignal()) on the engine.
Fonts appear as fallbacks (e.g. Times New Roman) when the required font files are not available on the server.
Solutions:
- Web fonts: Use Google Fonts or other CDN-hosted fonts in your HTML. These are downloaded by Chromium at render time.
- Local fonts: Install the font files on the server, or use
.WithFonts("path/to/fonts")to register them before rendering. - Docker: Include font files in your Docker image and install them with
fc-cache -f -v.
If you're using custom web fonts, ensure .WithWaitStrategy(WaitOptions.DefaultNetworkIdle) is enabled so Chromium finishes downloading them before capture.
Chromium processes can accumulate memory over many renders. CobaltPDF mitigates this by recycling browser instances after a configurable number of renders.
Solution: Reduce the recycle threshold and cap the pool size:
builder.Services.AddCobaltPdf(options => { options.PoolSize = 2; // fewer concurrent browsers options.RecycleAfter = 25; // recycle after 25 renders options.CloudEnvironment = CloudEnvironment.ConfigureForLowMemory; });
The ConfigureForLowMemory preset disables GPU compositing and reduces shared memory requirements.
The default render timeout is 30 seconds. Large pages with many images, complex layouts, or slow external resources may exceed this.
Solution: Increase the timeout for specific renders:
var pdf = await renderer .WithTimeout(TimeSpan.FromSeconds(60)) .RenderUrlAsPdfAsync(url);
If the page loads many external resources, consider using .WithWaitStrategy(WaitOptions.DefaultNetworkIdle) instead of a fixed delay, as it adapts to the actual load time.
Tip: Pass a CancellationToken to allow callers to cancel long-running renders gracefully.
Headers and footers require sufficient page margins to be visible. If margins are too small, Chromium clips the header/footer content.
Solution: Set explicit top and bottom margins that are large enough to contain your header/footer HTML:
var pdf = await renderer .WithHeader(headerHtml) .WithFooter(footerHtml) .WithMargins(top: "30mm", bottom: "25mm") .RenderUrlAsPdfAsync(url);
Header/footer templates are rendered in an isolated context with a fixed height. Use inline styles only — external stylesheets are not loaded in the header/footer context.
By default, Chromium does not print background colors and images when generating a PDF. This is the same behavior as the browser's print dialog.
Solution: Enable background printing:
var pdf = await renderer .WithPrintBackground() .RenderUrlAsPdfAsync(url);
If specific elements are hidden in print, check for @media print rules in your CSS that may be hiding them. You can also use .WithMediaType(CssMediaType.Screen) to force screen styles instead of print styles.
On its first ever render on a host, CobaltPDF.WebKit downloads, verifies, and extracts its portable WebKit bundle. This is a one-time cost — the extracted bundle is cached and reused for every subsequent render and application restart.
Solutions:
- Pre-warm at startup with
CobaltEngine.PreWarmAsync()so provisioning happens at boot, not on the first user request. - Bake the bundle into your image: ship a pre-extracted bundle inside your publish output (a
cobalt-webkit-bundlefolder next to your app), or point theCOBALT_INLINE_HOMEenvironment variable at one — useful for air-gapped hosts too. - Self-host the download on a private feed via
PoolOptions.BundleBaseUrlif your servers can't reach the public bundle host.
See the WebKit edition docs for details.
CobaltPDF.WebKit's rendering engine is Linux-native. On Windows it automatically renders through WSL2 (recommended) or Docker Desktop for development. If neither is available, the engine cannot render real PDFs on Windows.
Solutions:
- Install WSL2: run
wsl --installfrom an elevated terminal, restart, and the library will provision its bundle into your WSL distro automatically on first use. - Or install Docker Desktop: the library auto-pulls a small dev image and renders through it.
- Offline stub mode: in Debug builds the library can produce placeholder PDFs with no backend at all — useful for UI work on a plane, not for output verification.
Production note: deploy CobaltPDF.WebKit to Linux (Docker, Azure App Service Linux, AKS, ECS/Fargate, Ubuntu/Alpine). If you need native Windows production, use CobaltPDF (Chromium) — your license covers both libraries.
This can occur when PreWarmAsync() is called before the engine has fully initialised, or when the engine is disposed during pre-warming (e.g. during application shutdown).
Solution: Ensure Configure() completes before calling PreWarmAsync(). In ASP.NET Core, call it after Build():
var app = builder.Build(); // Configure first, then pre-warm CobaltEngine.Configure(CloudEnvironment.ConfigureForDocker); await app.Services .GetRequiredService<CobaltEngine>() .PreWarmAsync(); app.Run();
If the error occurs during shutdown, it can safely be caught and ignored — the browser processes are cleaned up regardless.