You are currently offline, serving cached version
10 December 2024 : If you are using angular-expressions to parse expressions such as {user.name}, {#users.length > 10}, please upgrade asap to angular-expressions@1.4.3 for security reasons : View Github issue

Error handling

This section is about how to handle Docxtemplater errors.

To be able to see these errors, you need to catch them properly.

function replaceErrors(key, value) {
    if (value instanceof Error) {
        return Object.getOwnPropertyNames(value).reduce(
            function (error, key) {
                error[key] = value[key];
                return error;
            },
            {}
        );
    }
    return value;
}

try {
    // render the document (replace all occurences of {first_name} by John, {last_name} by Doe, ...)
    doc.render();
} catch (error) {
    // The error thrown here contains additional information when logged with JSON.stringify (it contains a properties object containing all suberrors).
    console.log(JSON.stringify({ error }, replaceErrors));

    if (
        error.properties &&
        error.properties.errors instanceof Array
    ) {
        const errorMessages = error.properties.errors
            .map(function (error) {
                return error.properties.explanation;
            })
            .join("\n");
        console.log("errorMessages", errorMessages);
        // errorMessages is a humanly readable message looking like this:
        // 'The tag beginning with "foobar" is unopened'
    }
    throw error;
}

Error Schema

All errors thrown by docxtemplater follow this schema:

{
    name: One of [GenericError, TemplateError, ScopeParserError, InternalError, MultiError],
    message: The message of that error,
    properties : {
        explanation: An error that is user friendly (in english), explaining what failed exactly. This error could be shown as is to end users
        id: An identifier of the error that is unique for that type of Error
        ... : The other properties are specific to each type of error.
    }
}

Error example

If the content of your template is {user {name}, docxtemplater will throw the following error:

try {
    const doc = new Docxtemplater(zip, {
        paragraphLoop: true,
        linebreaks: true,
    });
    doc.render();
} catch (e) {
    console.log(
        // All these expressions are true
        e.name === "TemplateError",
        e.message === "Unclosed tag",
        e.properties.explanation ===
            "The tag beginning with '{user ' is unclosed",
        e.properties.id === "unclosed_tag",
        e.properties.context === "{user {",
        e.properties.xtag === "user "
    );
}

List of all Error Identifiers

All errors can be identified with their id (e.properties.id).

The ids are:

multi_error

This error means that multiple errors where found in the template (1 or more). See below for handling these errors.

unopened_tag

This error happens if a tag is closed but not opened. For example with the following template:

Hello name} !

unclosed_tag

This error happens if a tag is opened but not closed. For example with the following template:

Hello {name !

no_xml_tag_found_at_left (and no_xml_tag_found_at_right)

This error happens if a rawXMLTag doesn't find a <w:p> element

<w:p><w:t>{@raw}</w:t>
// Note that the `</w:p>` tag is missing.

utf8_decode

This is an internal error, please report it if you see it

xmltemplater_content_must_be_string

This is an internal error that happens if you try to template something that is not a string (a number for example)

raw_xml_tag_should_be_only_text_in_paragraph

This happens when a rawXMLTag {@raw} is not the only text in the paragraph. For example, writing {@raw} (Note the spaces) is not acceptable because the {@raw} tag replaces the full paragraph. We prefer to throw an Error now rather than have "strange behavior" because the spaces "disappeared".

To correct this error, you have to add manually the text that you want in your raw tag. (Or you can use the docxtemplater word-run module which adds a tag that can replace rawXML inside a tag).

Writing

{@my_first_tag}{my_second_tag}

Or even

Hello {@my_first_tag}

Is misusing docxtemplater.

The @ at the beginning means "replace the xml of the current paragraph with scope.my_first_tag" so that means that everything else in that Paragraph will be removed.

unclosed_loop (and unopened_loop)

This happens when a loop is closed but never opened: for example

{#users}{name}

or

{name}{/users}

closing_tag_does_not_match_opening_tag

This happens when a loop is closed but doesn't match the opening tag, for example:

{#users}{name}{/people}

scopeparser_compilation_failed

This happens when your parser throws an error during compilation. The parser is the second argument of the constructor new Docxtemplater(zip, {parser: function parser(tag) {}});

For example, if your template is:

{name++}

and you use the angular expression parser, you will have this error. The error happens when you call parser('name++'); The underlying error can be read in e.properties.rootError

unimplemented_tag_type

This happens when a tag type is not implemented. It should normally not happen, unless you changed docxtemplater code.

malformed_xml

This happens when an xml file of the document cannot be parsed correctly.

loop_position_invalid

This happens when a loop would produce invalid XML.

For example, if you write:

======================
| header1 | header2 |
----------------------
| {#users} | content |
======================

{/users}

this is not allowed since a loop that starts in a table must also end in that table.

Cannot attach a module that was already attached

You might get this error:

Cannot attach a module that was already attached: "ImageModule". Maybe you are
instantiating the module at the root level, and using it for multiple instances
of Docxtemplater

In previous versions the error was Cannot attach a module that was already attached.

This happens if you are reusing the same module instance twice.

It usually means that you are calling new ImageModule() just once, but you have to instantiate a new ImageModule instance for each docxtemplater instance.

The following code will throw the error when calling "generate" twice:

const Docxtemplater = require("docxtemplater");
const ImageModule = require("docxtemplater-image-module");

const imageOptions = {
    getImage(tagValue, tagName, meta) {
        console.log({ tagValue, tagName, meta });
        return fs.readFileSync(tagValue);
    },
    getSize() {
        // it also is possible to return a size in centimeters, like this : return [ "2cm", "3cm" ];
        return [150, 150];
    },
};

const imageModule = new ImageModule(imageOptions);

function generate(content) {
    const zip = new PizZip(content);
    const doc = new Docxtemplater(zip, {
        modules: [imageModule],
    });
    doc.render(data);
}

generate();
generate();

You must always reconstruct an imageModule for each Docxtemplater instance.

The following code will no more throw the error:

const Docxtemplater = require("docxtemplater");
const ImageModule = require("docxtemplater-image-module");
const imageOptions = {
    getImage(tagValue, tagName, meta) {
        console.log({ tagValue, tagName, meta });
        return fs.readFileSync(tagValue);
    },
    getSize() {
        // it also is possible to return a size in centimeters, like this : return [ "2cm", "3cm" ];
        return [150, 150];
    },
};

function generate(content) {
    const zip = new PizZip(content);
    const imageModule = new ImageModule(imageOptions);
    const doc = new Docxtemplater(zip, {
        paragraphLoop: true,
        linebreaks: true,
        modules: [imageModule],
    });
    doc.render(data);
}

generate();
generate();

Handling multiple errors

docxtemplater now has the ability to detect multiple errors in your template. If it detects multiple errors, it will throw an error that has the id multi_error

You can then write the following to view all errors:

try {
    doc.render();
} catch (e) {
    e.properties.errors.forEach(function (err) {
        console.log(err);
    });
}

Corrupt character error

It is possible that you can get the following error :

{
    message: "There are some XML corrupt characters",
    properties: {
        id: "invalid_xml_characters",
    }
}

This means that some characters in your data contains some strange character.

You can either make sure your data does not contain one of those invalid characters, or you can use a solution to remove all corruptCharacters from your data :

const corruptCharacters = /[\x00-\x08\x0B\x0C\x0E-\x1F]/g;
// 00    NUL '\0' (null character)
// 01    SOH (start of heading)
// 02    STX (start of text)
// 03    ETX (end of text)
// 04    EOT (end of transmission)
// 05    ENQ (enquiry)
// 06    ACK (acknowledge)
// 07    BEL '\a' (bell)
// 08    BS  '\b' (backspace)
// 0B    VT  '\v' (vertical tab)
// 0C    FF  '\f' (form feed)
// 0E    SO  (shift out)
// 0F    SI  (shift in)
// 10    DLE (data link escape)
// 11    DC1 (device control 1)
// 12    DC2 (device control 2)
// 13    DC3 (device control 3)
// 14    DC4 (device control 4)
// 15    NAK (negative ack.)
// 16    SYN (synchronous idle)
// 17    ETB (end of trans. blk)
// 18    CAN (cancel)
// 19    EM  (end of medium)
// 1A    SUB (substitute)
// 1B    ESC (escape)
// 1C    FS  (file separator)
// 1D    GS  (group separator)
// 1E    RS  (record separator)
// 1F    US  (unit separator)
function stripCorruptChars(str) {
    return str.replace(corruptCharacters, "");
}

function parser(tag) {
    return {
        get(scope) {
            let result = null;
            if (tag === ".") {
                result = scope;
            } else if (scope) {
                result = scope[tag];
            } else {
                result = scope;
            }
            if (typeof result === "string") {
                return stripCorruptChars(result);
            }
            return result;
        },
    };
}

const doc = new Docxtemplater(zip, {
    paragraphLoop: true,
    linebreaks: true,
    parser,
});
doc.render(/* data */);
Talk with sales Contact us