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

  1. Run epubcheck and repair the offending XHTML file in the epub.
  2. Re-export/re-convert the epub with a tool that emits well-formed XHTML.
  3. 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

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

Related errors


AI-assisted analysis of Kareadita/Kavita@9c3e540000 (2026-08-13). Data as JSON: /api/errors/8262eff00eede529. Report an issue: GitHub.