Closed syndrael closed 6 months ago
Hi @syndrael,
Thank you for reaching out. The error message you encountered, error in building plan while starting program: cannot query an empty range
, typically indicates that the start
time specified in your query is set in the future. This results in an empty range because there's no data to query from a future time point.
To address this and to properly handle similar errors, you can use structured error handling in your code. Below is an example using Python with our client that demonstrates how to handle exceptions gracefully using the ApiException
class. This approach ensures you can catch and analyze errors directly related to the API operations:
from influxdb_client import InfluxDBClient, Point
from influxdb_client.client.write_api import SYNCHRONOUS
from influxdb_client.rest import ApiException
with InfluxDBClient(url="http://localhost:8086", token="my-token", org="my-org", debug=False) as client:
test1 = Point("pullrequest").tag("key1", "value1").field("status", "value2")
test2 = Point("pullrequest").tag("key3", "value3").field("status", "value4")
# Write data using point structure
write_api = client.write_api(write_options=SYNCHRONOUS)
write_api.write(bucket="my-bucket", record=[test1, test2])
# Querying data using Table structure
query_api = client.query_api()
try:
tables = query_api.query('from(bucket:"my-bucket") |> range(start: 1916796352) |> filter(fn: (r) => r._measurement == "pullrequest")')
for table in tables:
for record in table.records:
print(record.values)
except ApiException as e:
print(f"Error message: {e.message}")
print(f"Body: {e.body}")
print(f"HTTP response status: {e.status}")
This script attempts to execute a query and handles any ApiException
that might arise, logging detailed error information. Adjust the range(start: ...)
value to a valid timestamp to avoid the specific error you're facing.
Let me know if this helps or if there's anything else you need!
Best Regards
@bednar Thank you for your answer. You're right. I had to to address this by handling an error. But i don't undertand why an empty answer wouldn't give empty "tables" (in your example). An empty answer forces us to manage exceptions and errors or learn how to manage dates. Wouldn't it be easier to return an empty element? In our case, e.body and e.status don't provide the expected result. e.status is a multi-line character string, unlike the statuses we're used to dealing with. I hope you understand me. Regards.
@bednar Thank you for your answer. You're right. I had to to address this by handling an error. But i don't undertand why an empty answer wouldn't give empty "tables" (in your example). An empty answer forces us to manage exceptions and errors or learn how to manage dates. Wouldn't it be easier to return an empty element? In our case, e.body and e.status don't provide the expected result. e.status is a multi-line character string, unlike the statuses we're used to dealing with. I hope you understand me. Regards.
The error originates from the InfluxDB Server, and the client simply propagates it. This behavior is consistent with how Flux operates. For more details, you can refer to this issue: https://github.com/influxdata/flux/issues/3543.
@bednar Thank you for this "root" cause. But :-) e.status is a multi-line character string, unlike the statuses we're used to dealing with. e.body and e.status don't provide the expected result. Can't the client correct it ? Regards
The e.status
returning 400
is the expected result for a bad request. You can enable debug mode by setting debug=True
to view HTTP responses from InfluxDB. If you want to learn how to properly handle exceptions, please refer to this example: https://github.com/influxdata/influxdb-client-python/blob/da7893615eaa1971086b5e7d517bcc283380c2d4/examples/connection_check.py#L25)
I understand that the error stems from the server and the API/Flux is just propagating it forward however it really does not make a whole lot of sense to throw an error there and I agree it should return as an empty table. Here's a pretty basic use case of why I think that:
Lets say I am paying for InfluxDB Cloud. The rates are dependent on my usage. My usage is dependent on the amount of queries I send. Due to the usage stats being taken into consideration, I optimize my code that way I am able to pass multiple queries all in one. It prevents my query count from growing for no reason and it provides better performance all around. Lets say I have 10 queries wrapped into one call. If ONE of those queries throws this error all 10 fail. So now instead of having bad results for just one table, Ive got bad results for all the tables. Kind of inconvenient, especially when I will have to pay more to prevent that from happening.
Also, what about a case where the InfluxDB hosts machine time is unable to sync properly. Let's say the InfluxDB server is idk ~10 sec behind the client. Now a SIGNIFICANTLY higher percentage of my queries will fail due to this since the timestamps the client is passing are in the future in the eyes of the InfluxDB Server. Obviously this is likely a rare case however in industrial settings where servers are behind firewalls and cant access all the things it needs to be able to do that, this certainly happens. I'm running into this issue now.
The error says "cannot query empty range". well then why can i query an empty range in the past and receive an empty table as a result??? Returning an empty table is the right move in this case and will provide streamlined results between ALL time ranges.
Specifications
Code sample to reproduce problem
Sorry but i don't know to "easily" reproduce. Code is very complex.
OK (there are data after Epoch 1714739400): from(bucket: "indicator") |> range(start: 1714739400) KO (there are no data after Epoch 1801139400): from(bucket: "indicator") |> range(start: 1801139400)
All i know is if how you try to query in a range where start is above every records, you get Error 400: But instead of e.status = 400 str(e.status).split("\n") gives this results
['(400)', 'Reason: Bad Request', "HTTP response headers: HTTPHeaderDict({'Content-Type': 'application/json; charset=utf-8', 'Vary': 'Accept-Encoding', 'X-Influxdb-Build': 'OSS', 'X-Influxdb-Version': 'v2.7.6', 'X-Platform-Error-Code': 'invalid', 'Date': 'Sat, 25 May 2024 09:32:30 GMT', 'Transfer-Encoding': 'chunked'})", 'HTTP response body: b\'{"code":"invalid","message":"error in building plan while starting program: cannot query an empty range"}\'', '']
type(e.status) --> <class 'influxdb_client.rest.ApiException'> type(e.body) --> <class 'NoneType'>It's like body was inside status
Expected behavior
type(e.status) --> int and e.body.. like every e.body.
Actual behavior
type(e.status) --> <class 'influxdb_client.rest.ApiException'> type(e.body) --> <class 'NoneType'>
str(e.status).split("\n") `['(400)', 'Reason: Bad Request', "HTTP response headers: HTTPHeaderDict({'Content-Type': 'application/json; charset=utf-8', 'Vary': 'Accept-Encoding', 'X-Influxdb-Build': 'OSS', 'X-Influxdb-Version': 'v2.7.6', 'X-Platform-Error-Code': 'invalid', 'Date': 'Sat, 25 May 2024 09:32:30 GMT', 'Transfer-Encoding': 'chunked'})", 'HTTP response body: b\'{"code":"invalid","message":"error in building plan while starting program: cannot query an empty range"}\'', '']
Additional info
No response