About This HTML Issue
A <th> gets its ARIA role from the table it belongs to, so it can't have a role attribute when that <table> has no role, or has role="table", role="grid" or role="treegrid".
In those tables the browser works out what each header cell is. A <th> inside <thead>, or in a row of headers above the data, is exposed as columnheader. A <th> at the start of a data row is exposed as rowheader. When the layout is ambiguous, scope="col" or scope="row" states the direction. Screen readers use these roles to announce the right header as the user moves from one data cell to the next.
The ARIA in HTML specification allows no role value at all on a <th> in these tables, so the validator reports this error whatever the value is. With role="columnheader" or role="rowheader" you also get a warning that the role is unnecessary for the element, and deleting the attribute clears both messages. Any other value replaces the header role. A sortable header marked role="button", or a header marked role="presentation", stops being a header, and screen readers no longer read its text before the cells it labels.
To make a column sortable, keep the <th> as it is, put a <button> inside it, and set aria-sort on the <th> for the column that is currently sorted. If the table exists only for layout, put role="presentation" on the <table> instead. A table with a role other than table, grid or treegrid loses its table semantics, and this rule no longer applies to its cells.
Table plugins and page builders often add a role to every part of a table: role="table" on the <table>, role="rowgroup" on <thead> and <tbody>, role="row" on each <tr> and role="cell" on each <td>. The validator reports all of them, with errors for the roles on <tr> and <td> and warnings for the rest, so remove them in the same change.
Invalid example
<table>
<thead>
<tr>
<th scope="col" role="columnheader">Product</th>
<th scope="col" role="button" tabindex="0">Price</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row" role="rowheader">Desk lamp</th>
<td>$45</td>
</tr>
<tr>
<th scope="row" role="rowheader">Notebook</th>
<td>$8</td>
</tr>
</tbody>
</table>
Valid example
<table>
<thead>
<tr>
<th scope="col">Product</th>
<th scope="col" aria-sort="descending">
<button type="button">Price</button>
</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Desk lamp</th>
<td>$45</td>
</tr>
<tr>
<th scope="row">Notebook</th>
<td>$8</td>
</tr>
</tbody>
</table>
Find issues like this automatically
Rocket Validator scans thousands of pages in seconds, detecting HTML issues across your entire site.