---
title: QUERY_WAS_CANCELLED_BY_CLIENT ClickHouse error
meta:
  description: Learn how to fix the QUERY_WAS_CANCELLED_BY_CLIENT error in ClickHouse and Tinybird. Understand what causes it and see examples of how to resolve it
---

# QUERY_WAS_CANCELLED_BY_CLIENT ClickHouse error

{% callout %}
This error occurs when a client application cancels a running query. It's common when clients implement timeout mechanisms, user cancellation, or connection management.
{% /callout %}

The `QUERY_WAS_CANCELLED_BY_CLIENT` error in ClickHouse (and Tinybird) happens when a client application explicitly cancels a running query. This is different from system-initiated cancellations and typically occurs when clients implement timeout mechanisms, user cancellation requests, connection management, or when the client application terminates unexpectedly.

## What causes this error

You'll typically see it when:

* Client application implements query timeout
* User manually cancels a query through the client
* Client connection is closed unexpectedly
* Application implements automatic cancellation for long-running queries
* Client-side resource constraints force cancellation
* Network issues cause client disconnection
* Application shutdown while queries are running
* Client implements retry logic that cancels previous attempts

{% callout type="tip" %}
This error indicates client-side cancellation rather than server-side issues. Check your application's query management logic.
{% /callout %}

## Example errors

```sql {% title="Fails: client timeout implementation" %}
SELECT COUNT(DISTINCT user_id) FROM events
WHERE timestamp >= '2020-01-01'
-- Error: Query was cancelled by client (timeout)
```

```sql {% title="Fails: user cancellation" %}
-- User cancels query in client application
SELECT * FROM large_table ORDER BY timestamp
-- Error: Query was cancelled by client
```

```sql {% title="Fails: connection management" %}
-- Client closes connection while query is running
SELECT
    user_id,
    COUNT(*) as event_count
FROM events
GROUP BY user_id
-- Error: Query was cancelled by client
```

```sql {% title="Fails: application shutdown" %}
-- Application shuts down during query execution
SELECT * FROM events WHERE timestamp > '2024-01-01'
-- Error: Query was cancelled by client
```

## How to fix it

### Check client timeout settings

Verify client-side timeout configurations:

```sql {% title="Check client settings" %}
-- In your client application, check timeout settings
-- Example for Python clickhouse-driver:
-- client = Client(host='host', port=9000, settings={'max_execution_time': 300})
```

### Review connection management

Ensure proper connection handling:

```sql {% title="Connection management" %}
-- Implement proper connection handling in your application
-- Example pseudo-code:
--
-- try:
--     with get_connection() as conn:
--         result = conn.execute(query)
--         return result
-- except ConnectionError:
--     # Handle connection issues
--     pass
```

### Implement proper error handling

Add cancellation handling to your application:

```sql {% title="Error handling" %}
-- In your application, handle cancellation gracefully
-- Example pseudo-code:
--
-- try:
--     result = execute_query(query)
--     return result
-- except QueryWasCancelledByClient:
--     # Handle client cancellation
--     logger.warning("Query cancelled by client")
--     return None
```

### Check client application logs

Review client-side logs for cancellation reasons:

```sql {% title="Client logging" %}
-- Enable detailed logging in your client application
-- Example for Python:
-- import logging
-- logging.basicConfig(level=logging.DEBUG)
```

## Common patterns and solutions

### Client timeout management

Implement proper timeout handling:

```sql {% title="Timeout configuration" %}
-- Set appropriate timeouts in your client
-- Example for Python clickhouse-driver:
from clickhouse_driver import Client

client = Client(
    host='your-host',
    port=9000,
    database='your_database',
    settings={
        'max_execution_time': 600,  -- 10 minutes
        'max_memory_usage': 10000000000,  -- 10GB
        'max_bytes_before_external_group_by': 1000000000  -- 1GB
    }
)
```

### Connection pooling

Use connection pooling to manage connections:

```sql {% title="Connection pooling" %}
-- Implement connection pooling in your application
-- Example pseudo-code:
--
-- class ConnectionPool:
--     def __init__(self, max_connections=10):
--         self.max_connections = max_connections
--         self.connections = []
--
--     def get_connection(self):
--         if self.connections:
--             return self.connections.pop()
--         return create_new_connection()
--
--     def return_connection(self, conn):
--         if len(self.connections) < self.max_connections:
--             self.connections.append(conn)
--         else:
--             conn.close()
```

### Query retry logic

Implement retry mechanisms for cancelled queries:

```sql {% title="Retry logic" %}
-- Add retry logic for client cancellations
-- Example pseudo-code:
--
-- max_retries = 3
-- base_delay = 1 second
--
-- for attempt in range(max_retries):
--     try:
--         result = execute_query(query)
--         return result
--     except QueryWasCancelledByClient:
--         if attempt < max_retries - 1:
--             delay = base_delay * (2 ** attempt)
--             time.sleep(delay)
--             continue
--         else:
--             raise
```

### Graceful shutdown

Handle application shutdown properly:

```sql {% title="Graceful shutdown" %}
-- Implement graceful shutdown in your application
-- Example pseudo-code:
--
-- import signal
--
-- def shutdown_handler(signum, frame):
--     # Cancel all running queries
--     cancel_all_queries()
--     # Close connections gracefully
--     close_all_connections()
--     sys.exit(0)
--
-- signal.signal(signal.SIGINT, shutdown_handler)
-- signal.signal(signal.SIGTERM, shutdown_handler)
```

## Tinybird-specific notes

In Tinybird, QUERY_WAS_CANCELLED_BY_CLIENT errors often occur when:

* API clients implement timeout mechanisms
* User cancels queries in the UI
* External applications close connections
* Network issues cause client disconnection
* Rate limiting forces client cancellation

To debug in Tinybird:

1. Check client timeout settings
2. Review network connectivity
3. Monitor API usage patterns
4. Check for rate limiting issues

{% callout type="tip" %}
In Tinybird, ensure your API clients have appropriate timeout settings and retry logic.
{% /callout %}

## Best practices

### Client configuration

* Set appropriate timeout values for different query types
* Implement proper connection pooling
* Use connection health checks
* Monitor client-side performance metrics

### Error handling

* Implement graceful cancellation handling
* Add retry logic with exponential backoff
* Log cancellation reasons for debugging
* Provide user feedback for cancelled operations

### Connection management

* Use connection pooling to reuse connections
* Implement connection health monitoring
* Handle connection failures gracefully
* Implement proper cleanup on shutdown

## Configuration options

### Client timeout settings

```sql {% title="Client timeout configuration" %}
-- Set various timeout parameters in your client
-- Example for Python clickhouse-driver:
client = Client(
    host='host',
    port=9000,
    settings={
        'max_execution_time': 300,  -- 5 minutes
        'max_query_size': 1000000000,  -- 1GB
        'max_memory_usage': 8000000000,  -- 8GB
        'max_bytes_before_external_group_by': 1000000000  -- 1GB
    }
)
```

### Connection settings

```sql {% title="Connection configuration" %}
-- Configure connection parameters
-- Example for Python clickhouse-driver:
client = Client(
    host='host',
    port=9000,
    database='database',
    user='user',
    password='password',
    settings={
        'connect_timeout': 10,  -- 10 seconds
        'send_receive_timeout': 300,  -- 5 minutes
        'sync_request_timeout': 300  -- 5 minutes
    }
)
```

### Query settings

```sql {% title="Query-specific settings" %}
-- Use settings for specific queries
-- Example for Python:
result = client.execute(
    "SELECT * FROM large_table SETTINGS max_execution_time = 600",
    settings={'max_execution_time': 600}
)
```

## Alternative solutions

### Asynchronous query execution

Use async patterns to avoid blocking:

```sql {% title="Async execution" %}
-- Use async/await patterns in your application
-- Example pseudo-code:
--
-- import asyncio
--
-- async def execute_query_async(query):
--     loop = asyncio.get_event_loop()
--     return await loop.run_in_executor(None, execute_query, query)
--
-- async def main():
--     tasks = []
--     for query in queries:
--         task = asyncio.create_task(execute_query_async(query))
--         tasks.append(task)
--
--     results = await asyncio.gather(*tasks, return_exceptions=True)
--     return results
```

### Query queuing

Implement query queuing for better control:

```sql {% title="Query queue" %}
-- Implement query queuing in your application
-- Example pseudo-code:
--
-- from queue import Queue
-- import threading
--
-- class QueryQueue:
--     def __init__(self):
--         self.queue = Queue()
--         self.worker_thread = threading.Thread(target=self._worker)
--         self.worker_thread.start()
--
--     def _worker(self):
--         while True:
--             query = self.queue.get()
--             if query is None:
--                 break
--             try:
--                 result = execute_query(query)
--                 query.set_result(result)
--             except Exception as e:
--                 query.set_exception(e)
--             finally:
--                 self.queue.task_done()
```

### Health monitoring

Implement health checks for connections:

```sql {% title="Health monitoring" %}
-- Add health checks to your connection management
-- Example pseudo-code:
--
-- def check_connection_health(connection):
--     try:
--         # Simple health check query
--         connection.execute("SELECT 1")
--         return True
--     except Exception:
--         return False
--
-- def get_healthy_connection():
--     for conn in connection_pool:
--         if check_connection_health(conn):
--             return conn
--     return create_new_connection()
```

## Monitoring and prevention

### Client performance tracking

```sql {% title="Performance monitoring" %}
-- Track client-side performance metrics
-- Example pseudo-code:
--
-- import time
--
-- def execute_query_with_monitoring(query):
--     start_time = time.time()
--     try:
--         result = execute_query(query)
--         duration = time.time() - start_time
--         log_metric('query_success', duration)
--         return result
--     except QueryWasCancelledByClient:
--         duration = time.time() - start_time
--         log_metric('query_cancelled_by_client', duration)
--         raise
```

### Cancellation analysis

```sql {% title="Cancellation tracking" %}
-- Track cancellation patterns in your application
-- Example pseudo-code:
--
-- class QueryTracker:
--     def __init__(self):
--         self.cancellations = []
--
--     def track_cancellation(self, query, reason, duration):
--         self.cancellations.append({
--             'query': query,
--             'reason': reason,
--             'duration': duration,
--             'timestamp': time.time()
--         })
--
--     def get_cancellation_stats(self):
--         return {
--             'total_cancellations': len(self.cancellations),
--             'avg_duration': sum(c['duration'] for c in self.cancellations) / len(self.cancellations),
--             'reasons': {c['reason']: sum(1 for x in self.cancellations if x['reason'] == c['reason']) for c in self.cancellations}
--         }
```

## See also

* [Connection Management](/forward/work-with-data/optimize)
* [Client Configuration](/forward/get-data-in/data-sources)
* [Error Handling](/forward/dev-reference/list-of-errors)
* [Performance Monitoring](/forward/monitoring)
