TheAlgorithms/Python · error · ValueError

Sudoku boards must be {NUM_SQUARES}x{NUM_SQUARES} squares.

Error message

Sudoku boards must be {NUM_SQUARES}x{NUM_SQUARES} squares.

What it means

Raised by is_valid_sudoku_board when the board is not exactly 9 rows of 9 cells each (NUM_SQUARES = 9). The validator checks outer length and every row's length before examining cell contents, so any 8x9, 9x10, or ragged board fails immediately. Content errors (bad values, duplicates) raise different errors later; this one is purely about geometry.

Source

Thrown at matrix/validate_sudoku_board.py:132

    ... ,["9","7","8","3","1","2","4","5","6"]
    ... ])
    True
    >>> is_valid_sudoku_board([["1", "2", "3", "4", "5", "6", "7", "8", "9"]])
    Traceback (most recent call last):
        ...
    ValueError: Sudoku boards must be 9x9 squares.
    >>> is_valid_sudoku_board(
    ...        [["1"], ["2"], ["3"], ["4"], ["5"], ["6"], ["7"], ["8"], ["9"]]
    ...  )
    Traceback (most recent call last):
        ...
    ValueError: Sudoku boards must be 9x9 squares.
    """
    if len(sudoku_board) != NUM_SQUARES or (
        any(len(row) != NUM_SQUARES for row in sudoku_board)
    ):
        error_message = f"Sudoku boards must be {NUM_SQUARES}x{NUM_SQUARES} squares."
        raise ValueError(error_message)

    row_values: defaultdict[int, set[str]] = defaultdict(set)
    col_values: defaultdict[int, set[str]] = defaultdict(set)
    box_values: defaultdict[tuple[int, int], set[str]] = defaultdict(set)

    for row in range(NUM_SQUARES):
        for col in range(NUM_SQUARES):
            value = sudoku_board[row][col]

            if value == EMPTY_CELL:
                continue

            box = (row // 3, col // 3)

            if (
                value in row_values[row]
                or value in col_values[col]
                or value in box_values[box]

View on GitHub (pinned to f5988cc097)

Solutions

  1. Slice the puzzle into rows of nine: board = [puzzle[i:i+9] for i in range(0, 81, 9)] before validating.
  2. If parsing digit strings, split each line into characters: [list(line) for line in lines] and verify you got exactly 9 lines.
  3. Add a quick assertion len(board) == 9 and all(len(r) == 9 for r in board) with row indices printed to locate the malformed row.
  4. Fix the source data: pad with the EMPTY_CELL marker or trim the stray cell so every row is exactly 9.

Example fix

# before
board = list("53..7....534.67...")  # flat 81-char list -> ValueError
is_valid_sudoku_board(board)

# after
board = [list(puzzle[i:i + 9]) for i in range(0, 81, 9)]
is_valid_sudoku_board(board)
Defensive patterns

Strategy: validation

Validate before calling

def is_9x9_board(board) -> bool:
    return (
        isinstance(board, list) and len(board) == 9
        and all(isinstance(row, list) and len(row) == 9 for row in board)
    )

if not is_9x9_board(board):
    raise ValueError("board must be 9 lists of 9 cells")
result = is_valid_sudoku_board(board)

Type guard

def is_sudoku_shape(board) -> bool:
    """Guard: list of exactly 9 rows, each a list of exactly 9 items."""
    return (
        isinstance(board, list)
        and len(board) == 9
        and all(isinstance(r, list) and len(r) == 9 for r in board)
    )

Try / catch

try:
    ok = is_valid_sudoku_board(board)
except ValueError as e:
    if "9x9" in str(e):
        board = [board[i:i + 9] for i in range(0, 81, 9)]  # reshape flat input
        ok = is_valid_sudoku_board(board)
    else:
        raise

Prevention

When it happens

Trigger: is_valid_sudoku_board([["1"]] * 8) (8 rows), a 9-row board where one row has 10 entries, boards built from strings without splitting into 9 characters, or nested lists flattened by a serialization step. The doctest itself shows [["1"], ["2"], ...] (nine 1-element rows) raising.

Common situations: Parsing a puzzle string like "53..7...." and passing it as one flat list/row instead of 9 rows of 9; missing or extra cells from OCR or manual entry; boards loaded from CSV with a truncated line; test fixtures with copy-paste errors.

Related errors


AI-assisted analysis of TheAlgorithms/Python@f5988cc097 (2026-08-14). Data as JSON: /api/errors/66b41a85d93fbbfb. Report an issue: GitHub.