swc-project/swc · warning · Error

No cell to close

Error message

No cell to close

What it means

In the "in cell" insertion mode, an end tag `caption`, `table`, `tbody`, `tfoot`, `thead`, or `tr` was seen while neither `td` nor `th` is in table scope. HTML5 defines this as a parse error ("no cell to close"); the token is ignored. It means a table-structure closer arrived when the cell it should implicitly close is already gone.

Source

Thrown at crates/swc_html_parser/src/parser/mod.rs:5590

                    Token::StartTag { tag_name, .. }
                        if matches!(
                            &**tag_name,
                            "caption"
                                | "col"
                                | "colgroup"
                                | "tbody"
                                | "td"
                                | "tfoot"
                                | "th"
                                | "thead"
                                | "tr"
                        ) =>
                    {
                        if !self.open_elements_stack.has_in_table_scope("td")
                            && !self.open_elements_stack.has_in_table_scope("th")
                        {
                            self.errors
                                .push(Error::new(token_and_info.span, ErrorKind::NoCellToClose));
                        } else {
                            self.close_the_cell();
                            self.process_token(token_and_info, None)?;
                        }
                    }
                    // An end tag whose tag name is one of: "body", "caption", "col", "colgroup",
                    // "html"
                    //
                    // Parse error. Ignore the token.
                    Token::EndTag { tag_name, .. }
                        if matches!(
                            &**tag_name,
                            "body" | "caption" | "col" | "colgroup" | "html"
                        ) =>
                    {
                        self.errors.push(Error::new(
                            token_and_info.span,
                            ErrorKind::StrayEndTag(tag_name.clone()),

View on GitHub (pinned to 5176682b65)

Solutions

  1. Simplify the nesting: remove leftover `</tr>`/`</tbody>`/`</table>` closers that no longer have a matching open element.
  2. Regenerate the table from data with a trusted template engine instead of patching broken markup.
  3. Validate with the W3C/WHATWG checker; it reports every unmatched structure closer with its position.
  4. Treat as recoverable for third-party content: the token is ignored; log the `NoCellToClose` entry from the `errors` vec and use the corrected tree.

Example fix

<!-- before: leftover </tr> after the row was already closed -->
<table><tr><td>a</td></tr></tr></table>

<!-- after -->
<table><tr><td>a</td></tr></table>
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check: structure closers without matching openers anywhere in the document
fn stray_structure_closers(html: &str) -> Vec<&'static str> {
    ["caption", "table", "tbody", "tfoot", "thead", "tr"]
        .into_iter()
        .filter(|t| html.matches(&format!("<{t}")).count() < html.matches(&format!("</{t}")).count())
        .collect()
}

Type guard

use swc_html_parser::error::{Error, ErrorKind};

fn is_no_cell_to_close(err: &Error) -> bool {
    matches!(err.kind(), ErrorKind::NoCellToClose)
}

Try / catch

let mut errors = Vec::new();
match parse_file_as_document(&fm, config, &mut errors) {
    Ok(doc) => {
        for e in errors.iter().filter(|e| matches!(e.kind(), ErrorKind::NoCellToClose)) {
            // token ignored per spec; tree recovered — log with span for upstream fix
        }
    }
    Err(fatal) => return Err(fatal.into()),
}

Prevention

When it happens

Trigger: Deeply malformed/nested tables where the open cell was already popped from table scope (e.g. by a nested `<table>` reset or duplicated section closers) before `</table>`, `</tbody>`, `</tfoot>`, `</thead>`, `</caption>`, or `</tr>` arrived — e.g. `<table><tr><td><table><tr><td>x</table></tr></table></tr></table>`-style leftover closers.

Common situations: Machine-generated tables (Excel/Word exports, report engines) with extra section/row closers; hand-nested tables where inner and outer closers get confused; sanitizer output that removed cells but kept structure closers.

Related errors


AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17). Data as JSON: /api/errors/66cc426628af43ba. Report an issue: GitHub.