{"record":{"id":"30d0180593a2eb21","repo":"BabylonJS/Babylon.js","slug":"att-after-start-tag-closed-for-ctx-name","errorCode":null,"errorMessage":"att() after start tag closed for <${ctx.name}>","messagePattern":"att\\(\\) after start tag closed for <(.+?)>","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/dev/serializers/src/3MF/core/xml/xml.builder.ts","lineNumber":138,"sourceCode":"        }\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\n                } else {\r\n                    this._registerNamespace(ctx, n, v);\r\n                    this._writeAttStr(`${ns}:${n}`, v);\r","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/serializers/src/3MF/core/xml/xml.builder.ts#L120-L156","documentation":"XmlBuilder.att() throws this error when the current element's start tag has already been closed (children or text started, or the tag was self-closed). XML attributes must appear inside the start tag, so once ctx.closed is true the attribute cannot be added and the builder refuses to emit invalid XML.","triggerScenarios":"Calling att() after text(), after a child element was opened, or after the element was closed/self-closed — anything that set ctx.closed before the attribute call.","commonSituations":"Streaming-style builder code where attributes are appended after content; accumulating attributes in a loop that runs after el()/text(); framework callbacks firing out of order (content written before attribute collection finished).","solutions":["Move all att() calls immediately after the element is opened and before text()/child elements.","Restructure the code to collect attributes first, then open the element with them.","Ensure no intermediate text() or child el() call occurs before all attributes are written.","If using helper wrappers, make sure they do not close the start tag implicitly before attributes are added."],"exampleFix":"// before\nb.el(\"item\").text(\"x\").att(null, \"id\", \"1\"); // throws\n// after\nb.el(\"item\").att(null, \"id\", \"1\").text(\"x\");","handlingStrategy":"validation","validationCode":"function canAddAttribute(b: XmlBuilder): boolean {\n    const ctx = (b as any)._peekContext?.();\n    return !!ctx && !ctx.closed;\n}\nif (canAddAttribute(b)) b.att(ns, name, value);","typeGuard":null,"tryCatchPattern":"try {\n    b.att(ns, name, value);\n} catch (e) {\n    if (e instanceof Error && e.message.startsWith('att() after start tag closed')) {\n        // collect attributes before opening the element and rewrite the section\n    } else throw e;\n}","preventionTips":["Emit all attributes immediately after opening the element.","Never interleave text() or child el() before the last att().","Collect attributes into an object first, then write them in one place.","Lint/review builder chains for attribute-after-content ordering."],"tags":["xml","api-misuse","builder","ordering"],"backgroundTag":"invalid-xml-structure","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}