BabylonJS/Babylon.js · error

att() without open element

Error message

att() without open element

What it means

XmlBuilder.att() writes an XML attribute, which is only legal while an element's start tag is open. The builder keeps a stack of open element contexts via _peekContext(); when the stack is empty (no open element), there is nowhere to attach the attribute, so it throws this error. This enforces correct XML structure at builder time.

Source

Thrown at packages/dev/serializers/src/3MF/core/xml/xml.builder.ts:135

        }
        if (standalone !== undefined) {
            this._writeAttStr(XmlSyntax.StandaloneKeyword, standalone ? "yes" : "no");
        }
        this._w.write(XmlSyntax.Question, XmlSyntax.CloseTag);
        return this;
    }

    /**
     *
     * @param ns
     * @param n
     * @param v
     * @returns
     */
    public att(ns: string | null, n: string, v: string): IXmlBuilder {
        const ctx = this._peekContext();
        if (!ctx) {
            throw new Error("att() without open element");
        }
        if (ctx.closed) {
            throw new Error(`att() after start tag closed for <${ctx.name}>`);
        }

        // explicit namespace declaration: xmlns or xmlns:prefix
        if (this._isXmlnsDecl(ns, n)) {
            if (n === XmlSyntax.Xmlns) {
                // default namespace
                ctx.defaultNs = v;
                // you can store default as empty prefix if you want
                this._registerNamespace(ctx, "", v);
                this._writeAttStr(XmlSyntax.Xmlns, v);
            } else {
                if (!ns) {
                    const prefix = n.slice(6); // "xmlns:"
                    this._registerNamespace(ctx, prefix, v);
                    this._writeAttStr(n, v);

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Call the element/open method before att(), and attach attributes before adding children or closing the element.
  2. Reorder builder calls so each att() follows its element() open call.
  3. Check for unbalanced close/at calls earlier in the builder chain that closed the element prematurely.
  4. Inspect _peekContext/state: ensure the element stack is non-empty at the att() call site.

Example fix

// before
const b = new XmlBuilder();
b.att(null, "id", "1"); // throws
// after
const b = new XmlBuilder();
b.el("model", null, null).att(null, "id", "1");
Defensive patterns

Strategy: try-catch

Try / catch

try {
    b.att(ns, name, value);
} catch (e) {
    if (e instanceof Error && e.message === 'att() without open element') {
        b.el('root').att(ns, name, value); // recover by opening the element first
    } else throw e;
}

Prevention

When it happens

Trigger: Calling att() before any element()/openElement call, or after the root element was fully closed, or after an unbalanced at()el()/close sequence emptied the element stack.

Common situations: Misordered builder calls (attributes emitted before the element); writing document-level content outside a root element; exception paths that closed elements early then continued adding attributes.

Related errors


AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30). Data as JSON: /api/errors/442f8139b394b287. Report an issue: GitHub.