Kareadita/Kavita · error · KavitaException
epub-malformed
Error message
epub-malformed
What it means
Thrown by BookService (ScopePage/GetBookPage path, line 1792) when an XHTML page has no <body> node AND HtmlDocument reports ParseErrors — i.e. the page's XHTML is malformed enough that the parser cannot find a body and also recorded parse errors. This is the hard-fail branch of book-page rendering; a missing body WITHOUT parse errors is auto-healed by synthesizing a <body>. The original parse errors are logged via LogBookErrors first.
Source
Thrown at Kavita.Services/BookService.cs:1792
var content = await contentFileRef.ReadContentAsync();
if (contentFileRef.ContentType != EpubContentType.XHTML_1_1) return content;
// In more cases than not, due to this being XML not HTML, we need to escape the script tags.
content = EscapeTags(content);
doc.LoadHtml(content);
var body = doc.DocumentNode.SelectSingleNode("//body");
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
if (body == null)
{
if (doc.ParseErrors.Any())
{
LogBookErrors(book, contentFileRef, doc);
throw new KavitaException("epub-malformed");
}
logger.LogError("{FilePath} has no body tag! Generating one for support. Book may be skewed", book.FilePath);
doc.DocumentNode.SelectSingleNode("/html").AppendChild(HtmlNode.CreateNode("<body></body>"));
body = doc.DocumentNode.SelectSingleNode("/html/body");
}
return await ScopePage(doc, book, apiBase, body!, mappings, page, ptocBookmarks, annotations, ct);
}
} catch (Exception ex)
{
logger.LogError(ex, "There was an issue reading one of the pages for {Book}", book.FilePath);
await mediaErrorService.ReportMediaIssueAsync(book.FilePath ?? string.Empty, MediaErrorProducer.BookService,
"There was an issue reading one of the pages for", ex, ct);
}
throw new KavitaException("epub-html-missing");
}
View on GitHub (pinned to 9c3e540000)
Solutions
- Run epubcheck and repair the offending XHTML file in the epub.
- Re-export/re-convert the epub with a tool that emits well-formed XHTML.
- If broad compatibility is needed, strengthen the lenient parse options or pre-sanitize the XHTML before LoadHtml.
Example fix
// before
if (body == null) {
if (doc.ParseErrors.Any()) {
LogBookErrors(book, contentFileRef, doc);
throw new KavitaException("epub-malformed");
}
// auto-heal path...
}
// after — attempt a best-effort body synthesis even when parse errors exist, report but don't hard-fail
if (body == null) {
LogBookErrors(book, contentFileRef, doc);
var html = doc.DocumentNode.SelectSingleNode("/html");
if (html != null) { html.AppendChild(HtmlNode.CreateNode("<body></body>")); body = doc.DocumentNode.SelectSingleNode("/html/body"); }
if (body == null) throw new KavitaException("epub-malformed");
} Defensive patterns
Strategy: validation
Validate before calling
// At import/scan, reject or flag epubs whose pages fail to parse
if (doc.ParseErrors.Any() && doc.DocumentNode.SelectSingleNode("//body") == null)
mediaErrorService.ReportMediaIssue(path, MediaErrorProducer.BookService, "malformed xhtml", null); Try / catch
catch (KavitaException ex) when (ex.Message == "epub-malformed") { /* surface a friendly 'book is corrupted' to the reader */ } Prevention
- Run epubcheck on the library to find malformed books proactively.
- Re-export epubs with a tool that emits well-formed XHTML.
- Surface MediaError records so users know which book needs repair.
When it happens
Trigger: Rendering an epub page (book reader) where the XHTML is malformed: unclosed tags, invalid entities, broken XML structure producing parse errors and no recoverable body.
Common situations: Poorly authored or badly converted epub; truncation of the XHTML inside the archive; non-XML-conformant HTML the lenient options cannot salvage.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Image file not found in epub: {imageKey}
- No images found on the specified page
- Image index {bookmarkDto.ImageOffset} is out of range. Page
- Image element does not have a valid source attribute
- Cannot copy external images
AI-assisted analysis of Kareadita/Kavita@9c3e540000 (2026-08-13).
Data as JSON: /api/errors/8262eff00eede529.
Report an issue: GitHub.