{"record":{"id":"442f8139b394b287","repo":"BabylonJS/Babylon.js","slug":"att-without-open-element","errorCode":null,"errorMessage":"att() without open element","messagePattern":"att\\(\\) without open element","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/dev/serializers/src/3MF/core/xml/xml.builder.ts","lineNumber":135,"sourceCode":"        }\r\n        if (standalone !== undefined) {\r\n            this._writeAttStr(XmlSyntax.StandaloneKeyword, standalone ? \"yes\" : \"no\");\r\n        }\r\n        this._w.write(XmlSyntax.Question, XmlSyntax.CloseTag);\r\n        return this;\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param ns\r\n     * @param n\r\n     * @param v\r\n     * @returns\r\n     */\r\n    public att(ns: string | null, n: string, v: string): IXmlBuilder {\r\n        const ctx = this._peekContext();\r\n        if (!ctx) {\r\n            throw new Error(\"att() without open element\");\r\n        }\r\n        if (ctx.closed) {\r\n            throw new Error(`att() after start tag closed for <${ctx.name}>`);\r\n        }\r\n\r\n        // explicit namespace declaration: xmlns or xmlns:prefix\r\n        if (this._isXmlnsDecl(ns, n)) {\r\n            if (n === XmlSyntax.Xmlns) {\r\n                // default namespace\r\n                ctx.defaultNs = v;\r\n                // you can store default as empty prefix if you want\r\n                this._registerNamespace(ctx, \"\", v);\r\n                this._writeAttStr(XmlSyntax.Xmlns, v);\r\n            } else {\r\n                if (!ns) {\r\n                    const prefix = n.slice(6); // \"xmlns:\"\r\n                    this._registerNamespace(ctx, prefix, v);\r\n                    this._writeAttStr(n, v);\r","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/serializers/src/3MF/core/xml/xml.builder.ts#L117-L153","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Call the element/open method before att(), and attach attributes before adding children or closing the element.","Reorder builder calls so each att() follows its element() open call.","Check for unbalanced close/at calls earlier in the builder chain that closed the element prematurely.","Inspect _peekContext/state: ensure the element stack is non-empty at the att() call site."],"exampleFix":"// before\nconst b = new XmlBuilder();\nb.att(null, \"id\", \"1\"); // throws\n// after\nconst b = new XmlBuilder();\nb.el(\"model\", null, null).att(null, \"id\", \"1\");","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    b.att(ns, name, value);\n} catch (e) {\n    if (e instanceof Error && e.message === 'att() without open element') {\n        b.el('root').att(ns, name, value); // recover by opening the element first\n    } else throw e;\n}","preventionTips":["Always open an element before writing attributes.","Order builder calls strictly: el -> att* -> text/children -> close.","Keep a helper that opens the root element first in every serialize function.","Validate builder call order in unit tests."],"tags":["xml","api-misuse","builder","state"],"backgroundTag":"invalid-xml-structure","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}