Samson
10/06/2025, 12:06 PMMarvin
10/06/2025, 12:06 PMMarvin
10/06/2025, 12:09 PMPREFECT_API_URL and PREFECT_API_KEY are unset in your environment.
2) Disable telemetry (optional, but recommended for air‑gapped/offline)
- Bash:
export PREFECT_DISABLE_TELEMETRY=1
unset PREFECT_API_URL
unset PREFECT_API_KEY
- PowerShell:
$env:PREFECT_DISABLE_TELEMETRY="1"
$env:PREFECT_API_URL=$null
$env:PREFECT_API_KEY=$null
3) Write and run your tasks/flows as normal
from prefect import task, flow, get_run_logger
from prefect.task_runners import ThreadPoolTaskRunner
@task
def add(a: int, b: int) -> int:
return a + b
@flow(task_runner=ThreadPoolTaskRunner())
def my_flow():
logger = get_run_logger()
result = add(1, 2) # runs locally, no API
<http://logger.info|logger.info>(f"Result: {result}")
return result
if __name__ == "__main__":
my_flow()
Notes and clarifications
- Calling a task inside a flow uses Prefect’s engine (retries, caching, timeouts, etc.) but still runs purely locally if you haven’t set an API.
- Calling a task outside a flow behaves like a normal Python function; orchestration features apply only within a flow run.
- Avoid Cloud-only helpers (e.g., creating artifacts or emitting events) when offline, as they require an API.
Docs and references
- Settings reference (env vars like PREFECT_API_URL, PREFECT_DISABLE_TELEMETRY): Prefect 3 Settings reference
- Connecting to Cloud (for contrast): Connect to Cloud
- Prefect 3 GA overview (local-first design): Prefect 3 GA blog
Are you on Prefect 3.x? If you’re on 2.x, the answer is still “yes” for local use, but the ergonomics differ slightly — happy to tailor the steps for your version.Samson
10/06/2025, 1:38 PMTraceback (most recent call last):
File
"/opt/homebrew/lib/python3.13/site-packages/marimo/_runtime/executor.py"
, line 138, in execute_cell
exec(cell.body, glbls)
~~~~^^^^^^^^^^^^^^^^^^
Cell <marimo://v2/dev.py#cell=cell-23>
, line 3, in <module>
error_df = fetch_measurements_for_user_day(error_uid, error_date)
File
"/opt/homebrew/lib/python3.13/site-packages/prefect/tasks.py"
, line 1002, in __call__
return run_task(
task=self,
...<2 lines>...
return_type=return_type,
)
File
"/opt/homebrew/lib/python3.13/site-packages/prefect/task_engine.py"
, line 1526, in run_task
return run_task_sync(**kwargs)
File
"/opt/homebrew/lib/python3.13/site-packages/prefect/task_engine.py"
, line 1333, in run_task_sync
with engine.start(task_run_id=task_run_id, dependencies=dependencies):
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File
"/opt/homebrew/Cellar/python@3.13/3.13.5/Frameworks/Python.framework/Versions/3.13/lib/python3.13/contextlib.py"
, line 141, in __enter__
return next(self.gen)
File
"/opt/homebrew/lib/python3.13/site-packages/prefect/task_engine.py"
, line 732, in start
with self.initialize_run(task_run_id=task_run_id, dependencies=dependencies):
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File
"/opt/homebrew/Cellar/python@3.13/3.13.5/Frameworks/Python.framework/Versions/3.13/lib/python3.13/contextlib.py"
, line 141, in __enter__
return next(self.gen)
File
"/opt/homebrew/lib/python3.13/site-packages/prefect/task_engine.py"
, line 655, in initialize_run
with SyncClientContext.get_or_create() as client_ctx:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
File
"/opt/homebrew/Cellar/python@3.13/3.13.5/Frameworks/Python.framework/Versions/3.13/lib/python3.13/contextlib.py"
, line 141, in __enter__
return next(self.gen)
File
"/opt/homebrew/lib/python3.13/site-packages/prefect/context.py"
, line 236, in get_or_create
with SyncClientContext() as ctx:
~~~~~~~~~~~~~~~~~^^
File
"/opt/homebrew/lib/python3.13/site-packages/prefect/context.py"
, line 218, in __enter__
self.client.raise_for_api_version_mismatch()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
File
"/opt/homebrew/lib/python3.13/site-packages/prefect/client/orchestration.py"
, line 3736, in raise_for_api_version_mismatch
raise RuntimeError(f"Failed to reach API at {self.api_url}") from e
RuntimeError: Failed to reach API at <http://127.0.0.1:4200/api/>Marvin
10/06/2025, 1:39 PMMarvin
10/06/2025, 1:40 PMprefect config view
- If you see PREFECT_API_URL = "<http://127.0.0.1:4200/api>" (or any URL), that’s the culprit.
2) Unset the API settings from your profile
- Run:
prefect config unset PREFECT_API_URL PREFECT_API_KEY PREFECT_UI_URL
prefect config validate
prefect config view
- After this, PREFECT_API_URL should be empty/absent. Prefect will then run locally with no API calls.
3) (Optional) Force offline in code for notebooks/cells
- If you want to be absolutely sure (or temporarily override a profile), wrap your call in `temporary_settings`:
from prefect.settings import temporary_settings, PREFECT_API_URL, PREFECT_API_KEY, PREFECT_DISABLE_TELEMETRY
with temporary_settings({
PREFECT_API_URL: None,
PREFECT_API_KEY: None,
PREFECT_DISABLE_TELEMETRY: True, # optional
}):
# call your Prefect task/flow here
error_df = fetch_measurements_for_user_day(error_uid, error_date)
A few notes
- Calling a task outside a flow is fine and should still be local/offline as long as no API URL is configured.
- If your task uses Cloud-only features (e.g., artifacts/events/variables) those will try to hit the API; avoid those calls when offline.
References
- Settings and profiles (env vars like PREFECT_API_URL, PREFECT_DISABLE_TELEMETRY): Prefect 3 Settings reference
If this still fails, could you share:
- The output of prefect version
- The lines containing PREFECT_API_* from prefect config view (no keys), so we can confirm the profile isn’t overriding your env.Samson
10/06/2025, 2:12 PMValueError: No Prefect API URL provided. Please set PREFECT_API_URL to the address of a running Prefect server.Marvin
10/06/2025, 2:12 PMMarvin
10/06/2025, 2:15 PM# write your logic as a plain function
def _fetch_measurements_for_user_day(uid, date):
...
# wrap it as a task for use in flows
from prefect import task, flow
fetch_measurements_for_user_day = task(_fetch_measurements_for_user_day)
# 1) PURE PYTHON (no Prefect engine, no API)
error_df = _fetch_measurements_for_user_day(error_uid, error_date)
# 2) PREFECT (inside a flow; see Option B if you want this offline)
@flow
def my_flow(uid, date):
return fetch_measurements_for_user_day(uid, date)
# my_flow(...) # runs with Prefect’s engine
Tip: If you already decorated the function with @task, you can either refactor as above or call the original undecorated function you factored out. This avoids any Prefect engine/client entirely.
Option B: Use Prefect’s engine locally without an external server
- Enable Prefect’s ephemeral server so Prefect can orchestrate locally without you running a separate server or connecting to Cloud.
- Then call your task from inside a @flow.
1) Ensure ephemeral mode is allowed and no API URL is set:
prefect config set PREFECT_SERVER_ALLOW_EPHEMERAL_MODE=true
prefect config unset PREFECT_API_URL PREFECT_API_KEY PREFECT_UI_URL
prefect config view
You should not see an API URL. Ephemeral mode being true lets Prefect start a local in-process API when needed.
2) Run your flow:
from prefect import task, flow
@task
def fetch_measurements_for_user_day(uid, date):
...
@flow
def run_once(uid, date):
return fetch_measurements_for_user_day(uid, date)
run_once(error_uid, error_date)
3) If you want to force this just in a cell/session, you can set it temporarily:
import os
os.environ["PREFECT_SERVER_ALLOW_EPHEMERAL_MODE"] = "true"
os.environ.pop("PREFECT_API_URL", None)
os.environ.pop("PREFECT_API_KEY", None)
Why you saw “No Prefect API URL provided”
- When a Prefect task is invoked, the engine creates a client. If there is no API URL and ephemeral mode is disabled, Prefect raises that error. This is expected behavior; enabling ephemeral mode fixes it, or bypassing the engine (Option A) avoids any client creation at all.
- Reference showing the error and ephemeral logic: GitHub issue 15818
If you truly never want any API overhead for these calls, Option A is the most direct: call the plain function (or the underlying function you factored out) instead of the @task object. If you’re okay with a temporary local API that Prefect spins up automatically, turn on ephemeral mode (Option B).
If it persists, can you share:
- prefect version
- The relevant lines from prefect config view for PREFECT_API_URL and PREFECT_SERVER_ALLOW_EPHEMERAL_MODE (no secrets)?