The documentation for using prefect.Client with Prefect Cloud ("Authenticating with Prefect Cloud") describes how a USER token can be provided by setting environment variable PREFECT__CLOUD__AUTH_TOKEN.
It also describes how to find available tenants, but I made the (incorrect) assumption that if I didn't explicitly set a tenant, the client would understand from my token which tenant I was trying to act in. When I tried to authenticate by only setting PREFECT__CLOUD__AUTH_TOKEN, I found that the client raises this hard-to-understand error:
Traceback (most recent call last):
File "", line 3, in
File "/Users/jlamb/miniconda3/lib/python3.6/site-packages/prefect/client/client.py", line 809, in create_project
input=dict(name=project_name, description=project_description)
File "/Users/jlamb/miniconda3/lib/python3.6/site-packages/prefect/client/client.py", line 226, in graphql
raise ClientError(result["errors"])
prefect.utilities.exceptions.ClientError: [{'path': ['create_project'], 'message': 'Unauthorized', 'extensions': {'code': 'FORBIDDEN'}}]
This is similar to #2810 , but I think it's a slightly different issue.
Now that I understand that a tenant id is required to make requests to Prefect Cloud, I expected to get an informative error message that said that. It wasn't obvious from the message above that the issue was a messing tenant_id on the request.
import os
# be sure ~/.prefect is not there (as it would be if you did 'prefect auth login')
prefect_config_dir = os.path.join(
os.environ["HOME"],
".prefect"
)
assert not os.path.isdir(prefect_config_dir)
os.environ["PREFECT__CLOUD__AUTH_TOKEN"] = # USER_TOKEN here #
import prefect
client = prefect.Client()
# _api_token should be set
assert client._api_token is not None
# should be connecting to cloud
assert client.api_server == "https://api.prefect.io/graphql"
# fails with the error in the description
client.create_project(
project_name="some-project",
project_description="c00l project"
)
prefect diagnostics
{
"config_overrides": {},
"env_vars": [],
"system_information": {
"platform": "Darwin-18.7.0-x86_64-i386-64bit",
"prefect_version": "0.10.7+1221.g4951cc22a",
"python_version": "3.6.10"
}
}
If Client has something like this in it, I think it would save users times by replacing a hard-to-understand error with an informative and prescriptive one:
using_cloud = server == prefect.context.config.cloud.get("graphql")
if using_cloud and self._active_tenant_id is None:
raise RuntimeError(
"Requests to Prefect Cloud require a tenant, and none is set. "
"Run client.login_to_tenant(client.get_default_tenant_slug()) in Python "
"or 'prefect auth login' in the CLI."
)
Thanks for your time and consideration
@jameslamb Thanks for opening the issue! Something along the lines of your proposed fix would suffice. I want to make sure we also support this feature when in the context of a run (using a RUNNER token) and not only Personal Access Tokens that are stored locally. I don't think we will encounter any weirdness there because RUNNER tokens are scoped to tenants but just something to check.
I'd like to come back and contribute this. I've learned a lot about prefect in the time since I opened this so I think I know enough to do this.
Also trying out mentioning @marvin-robot based on Jeremiah's post in Prefect Community Slack
I think you ought to know I鈥檓 feeling very depressed. Also, you're in the contest, @jameslamb.
Most helpful comment
I'd like to come back and contribute this. I've learned a lot about prefect in the time since I opened this so I think I know enough to do this.
Also trying out mentioning @marvin-robot based on Jeremiah's post in Prefect Community Slack