{"record":{"id":"6d5a287ffb06d9fe","repo":"swc-project/swc","slug":"start-tag-tag-name-seen-without-a-ruby-eleme","errorCode":null,"errorMessage":"Start tag \"{tag_name}\" seen without a \"ruby\" element being open","messagePattern":"Start tag \"(.+?)\" seen without a \"ruby\" element being open","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"crates/swc_html_parser/src/parser/mod.rs","lineNumber":4072,"sourceCode":"                    // implied end tags. If the current node is not now a ruby element, this is a\n                    // parse error.\n                    //\n                    // Insert an HTML element for the token.\n                    Token::StartTag {\n                        tag_name,\n                        is_self_closing,\n                        ..\n                    } if matches!(&**tag_name, \"rb\" | \"rtc\") => {\n                        let is_scope = self.open_elements_stack.has_in_scope(\"ruby\");\n\n                        if is_scope {\n                            self.open_elements_stack.generate_implied_end_tags();\n                        }\n\n                        match self.open_elements_stack.items.last() {\n                            Some(node) if !is_html_element!(node, \"ruby\") => {\n                                if !is_scope {\n                                    self.errors.push(Error::new(\n                                        token_and_info.span,\n                                        ErrorKind::StartTagSeenWithoutRuby(tag_name.clone()),\n                                    ));\n                                } else {\n                                    self.errors.push(Error::new(\n                                        token_and_info.span,\n                                        ErrorKind::UnclosedChildrenInRuby,\n                                    ));\n                                }\n                            }\n                            _ => {}\n                        }\n\n                        self.insert_html_element(token_and_info)?;\n                        maybe_allow_self_closing!(is_self_closing, tag_name);\n                    }\n                    // A start tag whose tag name is one of: \"rp\", \"rt\"\n                    //","sourceCodeStart":4054,"sourceCodeEnd":4090,"githubUrl":"https://github.com/swc-project/swc/blob/5176682b65416c6b5de6b47379ae1588ea3ecb3f/crates/swc_html_parser/src/parser/mod.rs#L4054-L4090","documentation":"A start tag `rb` or `rtc` was seen while no `ruby` element is in scope (parser/mod.rs:4066-4081). Ruby annotation tags are only meaningful inside `<ruby>`, so the spec makes this a parse error (`StartTagSeenWithoutRuby`); the parser still inserts the element, now as ordinary body content.","triggerScenarios":"`<rb>` or `<rtc>` appearing outside any `<ruby>`: e.g. `<p><rb>漢</rb></p>`, or ruby markup assembled from separate strings/fragments where the `<ruby>` wrapper is missing or was closed too early.","commonSituations":"Building CJK furigana/annotation markup programmatically (dictionaries, language-learning apps) and forgetting the `<ruby>` wrapper; parsing innerHTML fragments that were extracted from a ruby context; template partials that render only the `rb`/`rt` pieces.","solutions":["Wrap the annotation markup in `<ruby>...</ruby>`","Fix the component/fragment so `<rb>`/`<rtc>` are always rendered inside a ruby element","When parsing fragments, give the parser the correct context element so scoping matches the final document","Lint for rb/rt/rp/rtc tags that lack an ancestor ruby"],"exampleFix":"<!-- before -->\n<rb>漢</rb><rt>かん</rt>\n\n<!-- after -->\n<ruby><rb>漢</rb><rt>かん</rt></ruby>","handlingStrategy":"validation","validationCode":"// Ensure rb/rtc tokens appear only inside a <ruby> wrapper\nfn ruby_tags_orphaned(src: &str) -> bool {\n    let mut ruby = 0i32;\n    for tag in html_tag_tokens(src) {\n        match tag {\n            Start(ref n) if n == \"ruby\" => ruby += 1,\n            End(ref n) if n == \"ruby\" => ruby = ruby.saturating_sub(1),\n            Start(ref n) if matches!(n.as_str(), \"rb\"|\"rtc\") && ruby == 0 => return true,\n            _ => {}\n        }\n    }\n    false\n}","typeGuard":"fn is_rb_outside_ruby(e: &Error) -> bool {\n    matches!(\n        e.kind,\n        ErrorKind::StartTagSeenWithoutRuby(ref t) if matches!(&**t, \"rb\"|\"rtc\")\n    )\n}","tryCatchPattern":"let doc = parser.parse_document()?;\nif parser.take_errors().into_iter().any(is_rb_outside_ruby) {\n    return Err(ContentRejected::RubyMarkupMissingWrapper);\n}","preventionTips":["Always emit <ruby> before rb/rtc/rp/rt in renderers","Render ruby annotation as one atomic component, not loose fragments","Pass a correct context element when parsing innerHTML fragments of ruby markup"],"tags":["html","parser","ruby","rb","rtc","cjk","annotation"],"backgroundTag":"ruby-annotation-missing-parent","analyzedSha":"5176682b65416c6b5de6b47379ae1588ea3ecb3f","analyzedAt":"2026-08-17T16:16:52.067Z","contentChangedAt":"2026-08-17T16:16:52.067Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}