TABLE_IS_READ_ONLY ClickHouse error

This error occurs when you try to modify a table that is in read-only mode. This can happen due to system maintenance, permissions, or table engine constraints.

The TABLE_IS_READ_ONLY error in ClickHouse (and Tinybird) happens when you attempt to perform write operations (INSERT, UPDATE, DELETE, ALTER) on a table that is currently in read-only mode. This can occur due to various reasons including system maintenance, insufficient permissions, table engine limitations, or intentional configuration.

What causes this error

You'll typically see it when:

  • Attempting to INSERT into a read-only table
  • Trying to UPDATE or DELETE from a read-only table
  • Running ALTER statements on read-only tables
  • System maintenance mode is active
  • Insufficient user permissions
  • Table engine doesn't support writes
  • Table is in a read-only state due to configuration

Read-only tables can still be queried with SELECT statements. Only write operations are blocked.

Example errors

Fails: INSERT into read-only table
INSERT INTO read_only_table (id, name) VALUES (1, 'test')
-- Error: Table is in readonly mode
Fails: UPDATE read-only table
UPDATE read_only_table SET name = 'updated' WHERE id = 1
-- Error: Table is in readonly mode
Fails: DELETE from read-only table
DELETE FROM read_only_table WHERE id = 1
-- Error: Table is in readonly mode
Fails: ALTER read-only table
ALTER TABLE read_only_table ADD COLUMN new_column String
-- Error: Table is in readonly mode

How to fix it

Check table status

Verify if the table is actually read-only:

Check table engine and status
SELECT
    database,
    name,
    engine,
    engine_full,
    total_rows,
    total_bytes
FROM system.tables
WHERE database = currentDatabase()
  AND name = 'your_table_name'

Check table permissions

Verify your user permissions:

Check user permissions
SELECT
    user,
    database,
    table,
    grantee,
    privilege_type
FROM system.grants
WHERE table = 'your_table_name'

Check system settings

Look for read-only configurations:

Check read-only settings
SELECT
    name,
    value,
    description
FROM system.settings
WHERE name LIKE '%readonly%'

Verify table engine

Check if the table engine supports writes:

Check table engine capabilities
SELECT
    name,
    engine,
    engine_full
FROM system.tables
WHERE database = currentDatabase()

Common patterns and solutions

Temporary read-only state

Wait for maintenance to complete:

Check if maintenance is active
SELECT
    database,
    table,
    partition,
    name,
    active,
    modification_time
FROM system.parts
WHERE database = currentDatabase()
  AND table = 'your_table_name'

Permission issues

Request proper permissions or use appropriate user:

Check current user
SELECT currentUser() as current_user

Engine limitations

Use appropriate table engines for write operations:

Create writable table
CREATE TABLE writable_table (
    id UInt64,
    name String,
    created_at DateTime
) ENGINE = MergeTree()
ORDER BY id

System maintenance

Check system status and wait if needed:

Check system processes
SELECT
    query_id,
    user,
    query,
    state,
    start_time
FROM system.processes

Tinybird-specific notes

In Tinybird, TABLE_IS_READ_ONLY errors often occur when:

  • Data Sources are in maintenance mode
  • Workspace permissions are restricted
  • Data Sources are configured as read-only
  • System maintenance is in progress
  • API rate limits are exceeded

To debug in Tinybird:

  1. Check Data Source status in the UI
  2. Verify workspace permissions
  3. Check if maintenance is scheduled
  4. Contact support if the issue persists

In Tinybird, Data Sources can be temporarily read-only during maintenance or when rate limits are exceeded.

Best practices

Table design

  • Choose appropriate table engines for your use case
  • Plan for maintenance windows
  • Use proper permissions and access controls
  • Document table write requirements

Maintenance planning

  • Schedule maintenance during low-traffic periods
  • Communicate read-only periods to users
  • Implement proper backup strategies
  • Test maintenance procedures

Error handling

  • Implement retry logic for temporary read-only states
  • Use appropriate error messages for users
  • Monitor for read-only table states
  • Have fallback strategies for write operations

Troubleshooting steps

Step 1: Verify table state

Check table status
SELECT
    database,
    name,
    engine,
    total_rows,
    total_bytes
FROM system.tables
WHERE database = currentDatabase()
  AND name = 'your_table_name'

Step 2: Check permissions

Verify permissions
SELECT
    user,
    database,
    table,
    privilege_type
FROM system.grants
WHERE table = 'your_table_name'

Step 3: Check system status

System status check
SELECT
    name,
    value
FROM system.settings
WHERE name IN ('readonly', 'readonly_reason')

Step 4: Verify engine support

Engine capabilities
SELECT
    name,
    engine,
    engine_full
FROM system.tables
WHERE database = currentDatabase()

Alternative solutions

Use different table

Create a writable table for temporary operations:

Temporary writable table
CREATE TABLE temp_writable (
    id UInt64,
    data String
) ENGINE = Memory

-- Insert into temporary table
INSERT INTO temp_writable (id, data) VALUES (1, 'test')

-- Later merge with main table when it's writable
INSERT INTO main_table SELECT * FROM temp_writable

Batch operations

Wait for write access and perform batch operations:

Batch operations when available
-- Check if table is writable
SELECT count() FROM system.tables
WHERE database = currentDatabase()
  AND name = 'your_table_name'

-- If writable, perform batch insert
INSERT INTO your_table_name (id, name, timestamp) VALUES
(1, 'batch1', now()),
(2, 'batch2', now()),
(3, 'batch3', now())

Read-only alternatives

Use read-only operations while waiting:

Read operations while waiting
-- Analyze data without writing
SELECT
    COUNT(*) as total_records,
    COUNT(DISTINCT user_id) as unique_users,
    MIN(timestamp) as earliest_record,
    MAX(timestamp) as latest_record
FROM read_only_table
WHERE timestamp >= '2024-01-01'

See also

Updated