Kareadita/Kavita · error · KavitaException

epub-html-missing

Error message

epub-html-missing

What it means

Thrown as a terminal fallback after every attempt to render an epub page fails. The method extracts the HTML body node via XPath '/html/body', calls ScopePage, and if that throws or the body is null, the catch block logs the error, reports a MediaIssue, and then re-throws this generic 'epub-html-missing'. It is a KavitaException (UI-facing, not Sentry-reported), meaning the server treats it as a user-visible content problem rather than a server bug.

Source

Thrown at Kavita.Services/BookService.cs:1808

                    {
                        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");
    }

    /// <summary>
    /// Extracts the cover image to covers directory and returns file path back
    /// </summary>
    /// <param name="fileFilePath"></param>
    /// <param name="fileName">Name of the new file.</param>
    /// <param name="outputDirectory">Where to output the file, defaults to covers directory</param>
    /// <param name="encodeFormat">When saving the file, use encoding</param>
    /// <returns></returns>
    public string GetCoverImage(string fileFilePath, string fileName, string outputDirectory, EncodeFormat encodeFormat, CoverImageSize size = CoverImageSize.Default)
    {
        if (!IsValidFile(fileFilePath)) return string.Empty;

        if (Parser.IsPdf(fileFilePath))
        {
            return GetPdfCoverImage(fileFilePath, fileName, outputDirectory, encodeFormat, size);
        }

View on GitHub (pinned to 9c3e540000)

Solutions

  1. Open the epub in a standard reader (Calibre, Apple Books) to verify the file is valid; if it fails there too, the file is corrupt and must be re-acquired
  2. Unzip the epub and inspect the XHTML files inside OEBPS/ to confirm each has a well-formed <html><body> structure
  3. Run the epub through an epub validator (epubcheck) to identify structural defects
  4. If the file is valid but Kavita still fails, check the server logs for the underlying exception logged by logger.LogError just before this throw to find the real cause

Example fix

// The epub's XHTML must contain a standard body node.
// Before (malformed):
// <html><head>...</head></html>
// After:
// <html><head>...</head><body><p>Content</p></body></html>
Defensive patterns

Strategy: fallback

Validate before calling

// Validate epub structure before rendering:
// using var archive = ZipFile.OpenRead(epubPath);
// var htmlFile = archive.Entries.FirstOrDefault(e => e.FullName.EndsWith(".xhtml") || e.FullName.EndsWith(".html"));
// if (htmlFile == null) return ErrorResult("No HTML content found in epub");
// using var reader = new StreamReader(htmlFile.Open());
// var html = await reader.ReadToEndAsync();
// if (!html.Contains("<body")) return ErrorResult("epub HTML missing body element");

Try / catch

// Catch at the API controller level:
// try {
//     var page = await bookService.GetPage(bookId, page, apiKey, ct);
//     return Ok(page);
// } catch (KavitaException ex) when (ex.Message == "epub-html-missing") {
//     return BadRequest(new { error = "This epub file appears to be corrupt or has an unsupported structure." });
// }

Prevention

When it happens

Trigger: Reading any epub where the body element cannot be found (malformed HTML, non-standard structure, empty HTML file inside the archive), where the zip archive itself is corrupt and throws during extraction, or where ScopePage throws an inner exception that the catch swallows before this throw fires.

Common situations: Corrupt or hand-edited epub files with non-standard HTML structure; epub files generated by obscure conversion tools that omit a proper <body> tag; epub files whose internal HTML references resources that fail to load; disk I/O errors during archive extraction that cause the try block to fail.

Related errors


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