pub enum PdfServiceError {
InvalidUrl(String),
EmptyHtml,
PoolLockFailed(String),
BrowserUnavailable(String),
TabCreationFailed(String),
NavigationFailed(String),
NavigationTimeout(String),
PdfGenerationFailed(String),
Timeout(String),
PoolShuttingDown,
Internal(String),
}Expand description
Errors that can occur during PDF generation.
Each variant maps to a specific HTTP status code and error code for
consistent API responses. Use status_code() and
error_code() to build HTTP responses.
§HTTP Status Code Mapping
| Error Type | HTTP Status | Error Code |
|---|---|---|
InvalidUrl | 400 Bad Request | INVALID_URL |
EmptyHtml | 400 Bad Request | EMPTY_HTML |
PoolLockFailed | 500 Internal Server Error | POOL_LOCK_FAILED |
BrowserUnavailable | 503 Service Unavailable | BROWSER_UNAVAILABLE |
TabCreationFailed | 500 Internal Server Error | TAB_CREATION_FAILED |
NavigationFailed | 502 Bad Gateway | NAVIGATION_FAILED |
NavigationTimeout | 504 Gateway Timeout | NAVIGATION_TIMEOUT |
PdfGenerationFailed | 502 Bad Gateway | PDF_GENERATION_FAILED |
Timeout | 504 Gateway Timeout | TIMEOUT |
PoolShuttingDown | 503 Service Unavailable | POOL_SHUTTING_DOWN |
Internal | 500 Internal Server Error | INTERNAL_ERROR |
§Error Categories
§Client Errors (4xx)
These indicate problems with the request that the client can fix:
InvalidUrl- Malformed or missing URLEmptyHtml- Empty HTML content
§Server Errors (5xx)
These indicate problems on the server side:
PoolLockFailed- Internal synchronization issueTabCreationFailed- Browser tab creation failedInternal- Unexpected internal error
§Upstream Errors (502/504)
These indicate problems with the target URL or browser:
NavigationFailed- Failed to load the URLNavigationTimeout- URL took too long to loadPdfGenerationFailed- Browser failed to generate PDFTimeout- Overall operation timeout
§Availability Errors (503)
These indicate the service is temporarily unavailable:
BrowserUnavailable- No browsers available in poolPoolShuttingDown- Service is shutting down
§Examples
§Error Handling
use html2pdf_api::service::{PdfServiceError, ErrorResponse};
fn handle_result(result: Result<Vec<u8>, PdfServiceError>) -> (u16, String) {
match result {
Ok(pdf) => (200, format!("Generated {} bytes", pdf.len())),
Err(e) => {
let status = e.status_code();
let response = ErrorResponse::from(&e);
(status, serde_json::to_string(&response).unwrap())
}
}
}§Retry Logic
use html2pdf_api::service::PdfServiceError;
fn should_retry(error: &PdfServiceError) -> bool {
match error {
// Transient errors - worth retrying
PdfServiceError::BrowserUnavailable(_) => true,
PdfServiceError::NavigationTimeout(_) => true,
PdfServiceError::Timeout(_) => true,
// Client errors - don't retry
PdfServiceError::InvalidUrl(_) => false,
PdfServiceError::EmptyHtml => false,
// Server errors - maybe retry with backoff
PdfServiceError::PoolLockFailed(_) => true,
// Fatal errors - don't retry
PdfServiceError::PoolShuttingDown => false,
_ => false,
}
}Variants§
InvalidUrl(String)
The provided URL is invalid or malformed.
§Causes
- Empty URL string
- Missing URL scheme (e.g.,
example.cominstead ofhttps://example.com) - Invalid URL format
§Resolution
Provide a valid HTTP or HTTPS URL with proper formatting.
§Example Response
{
"error": "Invalid URL: relative URL without a base",
"code": "INVALID_URL"
}EmptyHtml
The HTML content is empty or contains only whitespace.
§Causes
- Empty
htmlfield in request - HTML field contains only whitespace
§Resolution
Provide non-empty HTML content.
§Example Response
{
"error": "HTML content is required",
"code": "EMPTY_HTML"
}PoolLockFailed(String)
Failed to acquire the browser pool lock.
This is an internal error indicating a synchronization problem, typically caused by a poisoned mutex (previous panic while holding lock).
§Causes
- Mutex was poisoned by a previous panic
- Deadlock condition (should not happen with correct implementation)
§Resolution
This is a server-side issue. Restarting the service may help. Check logs for previous panic messages.
No browser is available in the pool.
All browsers are currently in use and the pool is at maximum capacity.
§Causes
- High request volume exceeding pool capacity
- Slow PDF generation causing browser exhaustion
- Browsers failing health checks faster than replacement
§Resolution
- Retry after a short delay
- Increase
max_pool_sizeconfiguration - Reduce
waitsecsto speed up PDF generation
TabCreationFailed(String)
Failed to create a new browser tab.
The browser instance is available but couldn’t create a new tab.
§Causes
- Browser process is unresponsive
- System resource exhaustion (file descriptors, memory)
- Browser crashed
§Resolution
The pool should automatically replace unhealthy browsers. If persistent, check system resources and browser logs.
Failed to navigate to the specified URL.
The browser couldn’t load the target URL.
§Causes
- URL doesn’t exist (404)
- Server error at target URL (5xx)
- SSL/TLS certificate issues
- Network connectivity problems
- Target server refusing connections
§Resolution
- Verify the URL is accessible
- Check if the target server is running
- Verify SSL certificates if using HTTPS
Navigation to the URL timed out.
The browser started loading the URL but didn’t complete within the allowed time.
§Causes
- Target server is slow to respond
- Large page with many resources
- Network latency issues
- Target server overloaded
§Resolution
- Check target server performance
- Increase timeout if needed (via configuration)
- Optimize the target page
PdfGenerationFailed(String)
Failed to generate PDF from the loaded page.
The page loaded successfully but PDF generation failed.
§Causes
- Complex page layout that can’t be rendered
- Browser rendering issues
- Memory exhaustion during rendering
- Invalid page content
§Resolution
- Simplify the page layout
- Check for rendering errors in browser console
- Ensure sufficient system memory
Timeout(String)
The overall operation timed out.
The complete PDF generation operation (including queue time, navigation, and rendering) exceeded the maximum allowed duration.
§Causes
- High system load
- Very large or complex pages
- Slow target server
- Insufficient
waitsecsfor JavaScript completion
§Resolution
- Retry the request
- Increase timeout configuration
- Reduce page complexity
PoolShuttingDown
The browser pool is shutting down.
The service is in the process of graceful shutdown and not accepting new requests.
§Causes
- Service restart initiated
- Graceful shutdown in progress
- Container/pod termination
§Resolution
Wait for the service to restart and retry. Do not retry immediately as the service is intentionally stopping.
Internal(String)
Implementations§
Source§impl PdfServiceError
impl PdfServiceError
Sourcepub fn status_code(&self) -> u16
pub fn status_code(&self) -> u16
Returns the HTTP status code for this error.
Maps each error type to an appropriate HTTP status code following REST conventions.
§Status Code Categories
| Range | Category | Meaning |
|---|---|---|
| 400-499 | Client Error | Request problem (client can fix) |
| 500-599 | Server Error | Server problem (client can’t fix) |
§Examples
use html2pdf_api::service::PdfServiceError;
let error = PdfServiceError::InvalidUrl("missing scheme".to_string());
assert_eq!(error.status_code(), 400);
let error = PdfServiceError::BrowserUnavailable("pool exhausted".to_string());
assert_eq!(error.status_code(), 503);
let error = PdfServiceError::NavigationTimeout("30s exceeded".to_string());
assert_eq!(error.status_code(), 504);Sourcepub fn error_code(&self) -> &'static str
pub fn error_code(&self) -> &'static str
Returns a machine-readable error code.
These codes are stable and can be used for programmatic error handling
by API clients. They are returned in the code field of error responses.
§Error Codes
| Code | Error Type |
|---|---|
INVALID_URL | Invalid or malformed URL |
EMPTY_HTML | Empty HTML content |
POOL_LOCK_FAILED | Internal pool lock error |
BROWSER_UNAVAILABLE | No browsers available |
TAB_CREATION_FAILED | Failed to create browser tab |
NAVIGATION_FAILED | Failed to load URL |
NAVIGATION_TIMEOUT | URL load timeout |
PDF_GENERATION_FAILED | Failed to generate PDF |
TIMEOUT | Overall operation timeout |
POOL_SHUTTING_DOWN | Service shutting down |
INTERNAL_ERROR | Unexpected internal error |
§Examples
use html2pdf_api::service::PdfServiceError;
let error = PdfServiceError::InvalidUrl("test".to_string());
assert_eq!(error.error_code(), "INVALID_URL");
// Client-side handling
match error.error_code() {
"INVALID_URL" | "EMPTY_HTML" => println!("Fix your request"),
"BROWSER_UNAVAILABLE" | "TIMEOUT" => println!("Retry later"),
_ => println!("Contact support"),
}Sourcepub fn is_retryable(&self) -> bool
pub fn is_retryable(&self) -> bool
Returns true if this error is likely transient and worth retrying.
Transient errors are typically caused by temporary conditions that may resolve on their own. Client errors (4xx) are never transient as they require the client to change the request.
§Retryable Errors
| Error | Retryable | Reason |
|---|---|---|
BrowserUnavailable | ✅ | Pool may free up |
NavigationTimeout | ✅ | Network may recover |
Timeout | ✅ | Load may decrease |
PoolLockFailed | ✅ | Rare, may recover |
InvalidUrl | ❌ | Client must fix |
EmptyHtml | ❌ | Client must fix |
PoolShuttingDown | ❌ | Intentional shutdown |
§Examples
use html2pdf_api::service::PdfServiceError;
let error = PdfServiceError::BrowserUnavailable("pool full".to_string());
if error.is_retryable() {
// Wait and retry
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
}
let error = PdfServiceError::InvalidUrl("bad url".to_string());
assert!(!error.is_retryable()); // Don't retry, fix the URLTrait Implementations§
Source§impl Clone for PdfServiceError
impl Clone for PdfServiceError
Source§fn clone(&self) -> PdfServiceError
fn clone(&self) -> PdfServiceError
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for PdfServiceError
impl Debug for PdfServiceError
Source§impl Display for PdfServiceError
impl Display for PdfServiceError
Source§impl Error for PdfServiceError
impl Error for PdfServiceError
1.30.0 · Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
Source§impl From<&PdfServiceError> for ErrorResponse
impl From<&PdfServiceError> for ErrorResponse
Source§fn from(err: &PdfServiceError) -> Self
fn from(err: &PdfServiceError) -> Self
Source§impl From<PdfServiceError> for ErrorResponse
impl From<PdfServiceError> for ErrorResponse
Source§fn from(err: PdfServiceError) -> Self
fn from(err: PdfServiceError) -> Self
Auto Trait Implementations§
impl Freeze for PdfServiceError
impl RefUnwindSafe for PdfServiceError
impl Send for PdfServiceError
impl Sync for PdfServiceError
impl Unpin for PdfServiceError
impl UnwindSafe for PdfServiceError
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoCollection<T> for T
impl<T> IntoCollection<T> for T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> Paint for Twhere
T: ?Sized,
impl<T> Paint for Twhere
T: ?Sized,
Source§fn fg(&self, value: Color) -> Painted<&T>
fn fg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the foreground set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like red() and
green(), which have the same functionality but are
pithier.
§Example
Set foreground color to white using fg():
use yansi::{Paint, Color};
painted.fg(Color::White);Set foreground color to white using white().
use yansi::Paint;
painted.white();Source§fn bright_black(&self) -> Painted<&T>
fn bright_black(&self) -> Painted<&T>
Source§fn bright_red(&self) -> Painted<&T>
fn bright_red(&self) -> Painted<&T>
Source§fn bright_green(&self) -> Painted<&T>
fn bright_green(&self) -> Painted<&T>
Source§fn bright_yellow(&self) -> Painted<&T>
fn bright_yellow(&self) -> Painted<&T>
Source§fn bright_blue(&self) -> Painted<&T>
fn bright_blue(&self) -> Painted<&T>
Source§fn bright_magenta(&self) -> Painted<&T>
fn bright_magenta(&self) -> Painted<&T>
Source§fn bright_cyan(&self) -> Painted<&T>
fn bright_cyan(&self) -> Painted<&T>
Source§fn bright_white(&self) -> Painted<&T>
fn bright_white(&self) -> Painted<&T>
Source§fn bg(&self, value: Color) -> Painted<&T>
fn bg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the background set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like on_red() and
on_green(), which have the same functionality but
are pithier.
§Example
Set background color to red using fg():
use yansi::{Paint, Color};
painted.bg(Color::Red);Set background color to red using on_red().
use yansi::Paint;
painted.on_red();Source§fn on_primary(&self) -> Painted<&T>
fn on_primary(&self) -> Painted<&T>
Source§fn on_magenta(&self) -> Painted<&T>
fn on_magenta(&self) -> Painted<&T>
Source§fn on_bright_black(&self) -> Painted<&T>
fn on_bright_black(&self) -> Painted<&T>
Source§fn on_bright_red(&self) -> Painted<&T>
fn on_bright_red(&self) -> Painted<&T>
Source§fn on_bright_green(&self) -> Painted<&T>
fn on_bright_green(&self) -> Painted<&T>
Source§fn on_bright_yellow(&self) -> Painted<&T>
fn on_bright_yellow(&self) -> Painted<&T>
Source§fn on_bright_blue(&self) -> Painted<&T>
fn on_bright_blue(&self) -> Painted<&T>
Source§fn on_bright_magenta(&self) -> Painted<&T>
fn on_bright_magenta(&self) -> Painted<&T>
Source§fn on_bright_cyan(&self) -> Painted<&T>
fn on_bright_cyan(&self) -> Painted<&T>
Source§fn on_bright_white(&self) -> Painted<&T>
fn on_bright_white(&self) -> Painted<&T>
Source§fn attr(&self, value: Attribute) -> Painted<&T>
fn attr(&self, value: Attribute) -> Painted<&T>
Enables the styling Attribute value.
This method should be used rarely. Instead, prefer to use
attribute-specific builder methods like bold() and
underline(), which have the same functionality
but are pithier.
§Example
Make text bold using attr():
use yansi::{Paint, Attribute};
painted.attr(Attribute::Bold);Make text bold using using bold().
use yansi::Paint;
painted.bold();Source§fn rapid_blink(&self) -> Painted<&T>
fn rapid_blink(&self) -> Painted<&T>
Source§fn quirk(&self, value: Quirk) -> Painted<&T>
fn quirk(&self, value: Quirk) -> Painted<&T>
Enables the yansi Quirk value.
This method should be used rarely. Instead, prefer to use quirk-specific
builder methods like mask() and
wrap(), which have the same functionality but are
pithier.
§Example
Enable wrapping using .quirk():
use yansi::{Paint, Quirk};
painted.quirk(Quirk::Wrap);Enable wrapping using wrap().
use yansi::Paint;
painted.wrap();Source§fn clear(&self) -> Painted<&T>
👎Deprecated since 1.0.1: renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
fn clear(&self) -> Painted<&T>
resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.Source§fn whenever(&self, value: Condition) -> Painted<&T>
fn whenever(&self, value: Condition) -> Painted<&T>
Conditionally enable styling based on whether the Condition value
applies. Replaces any previous condition.
See the crate level docs for more details.
§Example
Enable styling painted only when both stdout and stderr are TTYs:
use yansi::{Paint, Condition};
painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);