overleaf/overleaf · error

\hline must be at the start of a row

Error message

\hline must be at the start of a row

What it means

The table-generator parses LaTeX tabular bodies into a row/cell structure and allows \hline only at the start of a row (before any cell content). When an \hline appears after a cell that already has non-empty content, parseTabularBody throws this error because it cannot represent a mid-row hline in its model. It is thrown to reject tabular structures (e.g. \hline separating cells within one row) that the table generator does not support.

Source

Thrown at services/web/frontend/js/features/source-editor/components/table-generator/utils.ts:392

      if (!lastCell?.multiColumn) {
        if (lastCell) {
          if (lastCell.content.trim() === '') {
            lastCell.position.from = currentChild.to
            lastCell.position.to = currentChild.to
          } else {
            lastCell.content += state.sliceDoc(
              currentChild.from,
              currentChild.to
            )
            lastCell.position.to = currentChild.to
          }
        }
      }
      // Try to preserve whitespace by skipping past it when locating cells
    } else if (isHLine(currentChild)) {
      const lastCell = getLastCell()
      if (lastCell?.content.trim()) {
        throw new Error('\\hline must be at the start of a row')
      }
      // push start of cell past the hline
      if (lastCell) {
        lastCell.position.from = currentChild.to
        lastCell.position.to = currentChild.to
      }
      const lastRow = getLastRow()
      lastRow.hlines.push({
        position: { from: currentChild.from, to: currentChild.to },
        // They will always be at the top, we patch the bottom border later.
        atBottom: false,
      })
    } else {
      // Add to the last cell
      if (!getLastCell()) {
        getLastRow().cells.push({
          content: '',
          position: { from: currentChild.from, to: currentChild.from },

View on GitHub (pinned to 28ad3b03b7)

Solutions

  1. Add a row separator `\\` immediately before the misplaced \hline so it starts a new row
  2. Remove the redundant \hline if it duplicates an existing rule at the row boundary
  3. Rewrite the row so all \hline commands appear only at the start of rows

Example fix

// before
\begin{tabular}{ll}
  a & b \hline \\
  c & d
\end{tabular}
// after
\begin{tabular}{ll}
  \hline
  a & b \\
  \hline
  c & d
\end{tabular}
Defensive patterns

Strategy: validation

Validate before calling

function validateHlinePositions(latexBody) {
  // every \hline must be preceded (ignoring whitespace) by a row end
  return !/[^\\](\s|\n)*\\hline/.test(latexBody.replace(/\\\\[\s\S]*?\\hline/g, '')) &&
    !/(?<![\\\\][ \t]*\n)[ \t]*\S[^\n]*\\hline/.test(latexBody);
}
// simpler practical check: each \\hline must follow a \\ line break or \begin{tabular}

Prevention

When it happens

Trigger: Calling tableData/generateTable on a tabular body where an \hline node appears after a cell with non-trimmed content in the same row, e.g. `a & b \\hline \\ c` or `a \hline` instead of `a \\ \hline`.

Common situations: Hand-written LaTeX pasted into the source editor where \hline was used without a row-ending `\\` before it; mixing multirow/multicolumn hand-edits; editors converting tables that place rules mid-row.

Related errors


AI-assisted analysis of overleaf/overleaf@28ad3b03b7 (2026-09-03). Data as JSON: /api/errors/9d2bcc4f396106bc. Report an issue: GitHub.