MiniMax-AI/skills · critical · InvalidOperationException

Document has no main part.

Error message

Document has no main part.

What it means

`doc.MainDocumentPart ?? throw new InvalidOperationException("Document has no main part.")` at the top of `CommentSynchronizer.AddComment`. `MainDocumentPart` (holding `word/document.xml`) is null on a document opened/created without one, so the method cannot place comment range markers in the body and aborts.

Source

Thrown at skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/CommentSynchronizer.cs:19

using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;

namespace MiniMaxAIDocx.Core.OpenXml;

/// <summary>
/// Manages the 4-file comment system (comments.xml, commentsExtended.xml,
/// commentsIds.xml, commentsExtensible.xml) plus document.xml markers.
/// </summary>
public static class CommentSynchronizer
{
    /// <summary>
    /// Adds a comment to the document, updating all required parts.
    /// </summary>
    public static int AddComment(WordprocessingDocument doc, string text, string author, string rangeBookmark)
    {
        var mainPart = doc.MainDocumentPart
            ?? throw new InvalidOperationException("Document has no main part.");

        int commentId = GetNextCommentId(doc);

        // Ensure comments part exists
        var commentsPart = mainPart.WordprocessingCommentsPart
            ?? mainPart.AddNewPart<WordprocessingCommentsPart>();

        if (commentsPart.Comments == null)
            commentsPart.Comments = new Comments();

        // Create the comment
        var comment = new Comment
        {
            Id = commentId.ToString(),
            Author = author,
            Date = DateTime.UtcNow,
            Initials = author.Length > 0 ? author[..1].ToUpperInvariant() : "A"
        };

View on GitHub (pinned to 60aaae52bb)

Solutions

  1. Seed the main part when creating: `var main = doc.AddMainDocumentPart(); main.Document = new Document(new Body());` before `AddComment`.
  2. Open from a valid `.docx` and guard `if (doc.MainDocumentPart is null) { /* recreate from template */ }` first.
  3. Ensure the document is not already disposed before calling.

Example fix

// before
using var doc = WordprocessingDocument.Create(p, WordprocessingDocumentType.Document);
CommentSynchronizer.AddComment(doc, "note", "me", "bm"); // throws

// after
using var doc = WordprocessingDocument.Create(p, WordprocessingDocumentType.Document);
var main = doc.AddMainDocumentPart();
main.Document = new Document(new Body());
CommentSynchronizer.AddComment(doc, "note", "me", "bm");
Defensive patterns

Strategy: validation

Validate before calling

static void EnsureReady(WordprocessingDocument doc)
{
    if (doc.MainDocumentPart is null)
    {
        var main = doc.AddMainDocumentPart();
        main.Document = new Document(new Body());
    }
}

// call before AddComment
EnsureReady(doc);
int id = CommentSynchronizer.AddComment(doc, text, author, rangeBookmark);

Type guard

static bool IsDocumentReady(WordprocessingDocument doc) =>
    doc.MainDocumentPart is not null;

Try / catch

try
{
    return CommentSynchronizer.AddComment(doc, text, author, rangeBookmark);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("no main part"))
{
    var main = doc.AddMainDocumentPart();
    main.Document = new Document(new Body());
    return CommentSynchronizer.AddComment(doc, text, author, rangeBookmark);
}

Prevention

When it happens

Trigger: Calling `AddComment` on a `WordprocessingDocument` created via `WordprocessingDocument.Create(...)` without a follow-up `AddMainDocumentPart()`, or on a malformed `.docx` package missing `word/document.xml`.

Common situations: Newly created documents that were never seeded with a main part, opening template/empty shells, or operating on a disposed/closed document handle.

Related errors


AI-assisted analysis of MiniMax-AI/skills@60aaae52bb (2026-08-13). Data as JSON: /api/errors/b35339231437d8e3. Report an issue: GitHub.