<@ULVA73B9P> what is the correct way to get access...
# ask-marvin
s
@Marvin what is the correct way to get access to the result of a PrefectFuture, if I want to check if the result is True or False?
m
thought for 186.5 seconds
Short answer: call
.result()
on the
PrefectFuture
. In Prefect 3.x: -
.result()
blocks until the task finishes and returns the original value, so you can use it directly in an
if
check. - You can control behavior with
timeout
and
raise_on_failure
. Examples:
Copy code
from prefect import flow, task

@task
def is_ready(x):
    return x > 0

@flow
def main():
    fut = is_ready.submit(5)

    # Basic: raises if the task failed
    flag = fut.result()
    if flag:
        print("Result is True")
    else:
        print("Result is False")
Handle failures explicitly:
Copy code
try:
    flag = fut.result(timeout=30)  # seconds
    if flag:
        ...
except Exception as exc:
    # The task failed or timed out
    ...
Non-raising variant (inspect state yourself):
Copy code
flag = fut.result(raise_on_failure=False)
if fut.state.is_failed():
    # handle failure
else:
    if flag:
        ...
Resolve futures in nested structures:
Copy code
from prefect.futures import resolve_futures_to_results

flag = resolve_futures_to_results(fut)
if flag:
    ...
Tip: Don’t check the future itself (e.g.,
if fut:
) — that won’t resolve it. Always use
fut.result()
(or
resolve_futures_to_results
).
s
@Marvin does this method work in Prefect 2.20.16?
m
thought for 21.0 seconds
Yes. In Prefect 2.20.16 you can use
PrefectFuture.result()
the same way: -
future.result()
blocks and returns the underlying value (so you can check True/False directly) - Supports
timeout
and
raise_on_failure
Example:
Copy code
from prefect import flow, task

@task
def is_ready(x):
    return x > 0

@flow
def main():
    fut = is_ready.submit(5)
    flag = fut.result(timeout=30, raise_on_failure=True)
    if flag:
        print("Result is True")
    else:
        print("Result is False")
If you want to avoid raising on failure and inspect the state:
Copy code
flag = fut.result(raise_on_failure=False)
state = fut.state
if state.is_failed():
    # handle failure
else:
    if flag:
        ...
If you have futures nested in structures,
prefect.futures.resolve_futures_to_results(...)
is also available in 2.20.16. Note: Prefect 3.x keeps this pattern; consider upgrading when you’re ready.
s
@Marvin what method do you suggest, should I check is_failed(), is_completed() or use fut.result()?
Copy code
if fut.result() is False:
   ...
m
thought for 34.7 seconds
Short recommendation: - If you want failures to surface as errors, use
fut.result()
and then check the boolean. - If you need to distinguish a task failure from a False result (and avoid an exception), use
fut.result(raise_on_failure=False)
and inspect the state first. Patterns: 1) Simplest (treat failure as error)
Copy code
flag = fut.result()  # raises if the task failed
if flag is False:    # or: if not flag
    ...
2) Distinguish failure from False
Copy code
flag = fut.result(raise_on_failure=False)
if fut.state.is_failed():
    # handle the failure path
else:
    if flag is False:  # or: if not flag
        ...
Notes: -
is_completed()
only tells you the task succeeded; you still need
.result()
to read the value. - Using
is False
is a strict boolean check; use
if not flag
if you want to treat other falsy values (0, "", [], None) the same as False. If you share whether you want to handle failures differently from a False result or avoid blocking, I can tailor the pattern further.
s
@Marvin I have tried
Copy code
if not fut.result():
   ...
and on for one of the futures it didn't equate to
True
so I used instead.
Copy code
if fut.result() is False:
   ...
What could be the reason for this?
m
thought for 35.5 seconds
Most likely cause: you’re mixing “truthiness” with “is exactly False”. - not x checks truthiness. It will treat many values as False: 0, 0.0, "", [], {}, None, and some library booleans (e.g., numpy.bool_(False)). - x is False only matches the single Python False object. So if your task returned a falsy non-boolean (e.g., 0 or ""), then: - not fut.result() will be True - fut.result() is False will be False If you saw the opposite behavior, the value may be a custom type with unusual truthiness or a non-Python boolean (e.g., NumPy/Pandas) that doesn’t behave like you expect. What to do: - If the task is meant to return a real Python bool, coerce it in the task:
Copy code
return bool(value)
- Choose your check based on intent: - Treat any falsy value as negative:
Copy code
flag = fut.result()
if not flag:
    ...
- Only treat literal False as negative:
Copy code
flag = fut.result()
if flag is False:
    ...
- If you need to distinguish failures from False, avoid exceptions:
Copy code
flag = fut.result(raise_on_failure=False)
if fut.state.is_failed():
    # handle failure
elif flag is False:
    ...
If you can, print the actual type/value to confirm what you’re getting:
Copy code
val = fut.result()
print(type(val), repr(val))
Share that output and I can suggest the most robust check for your case.
s
@Marvin the task returns a
State
object
m
thought for 72.3 seconds
Ah—that explains it.
fut.result()
gives you whatever the task returned. If your task returns a Prefect
State
, then: -
not fut.result()
is checking the truthiness of a State object (custom objects are truthy by default), so it will be False. -
fut.result() is False
checks identity with the singleton `False`; a
State
object is never the
False
object, so this will also be False. In other words, both checks aren’t looking at the boolean you care about—they’re just looking at the fact you returned a
State
object. What to do instead depends on your intent: A) You want to know if the task execution succeeded/failed - Check the future’s run state (not the returned value):
Copy code
if fut.state.is_failed():
    ...
elif fut.state.is_completed():
    ...
B) You want a True/False value produced by the task - Don’t return a
State
from the task—return a real boolean:
Copy code
@task
def is_ready(...):
    return bool(some_condition)

flag = fut.result()
if not flag:
    ...
C) You intentionally returned a State and need the value inside it - Extract the inner value from that returned State:
Copy code
from prefect.states import get_state_result

inner_state = fut.result()  # this is a State
value = get_state_result(inner_state, raise_on_failure=False)

if inner_state.is_failed():
    # handle inner failure
elif value is False:
    ...
Important note: Returning a
State
from a task does not set the task’s run state—Prefect manages the run state separately. Use exceptions to fail a task or just return your data value (e.g., a bool) and inspect it.
s
@Marvin if the returned value is either
Completed()
or
Failed(message="Failed to do xyz")
should I be doing the following?
Copy code
if fut.state.is_failed():
    ...
elif fut.state.is_completed():
    ...
m
thought for 26.5 seconds
Short answer: - If you want to know whether the task run itself succeeded/failed, your snippet is correct:
Copy code
if fut.state.is_failed():
    ...
elif fut.state.is_completed():
    ...
- If your task returns a State object as its value (e.g.,
Completed()
or
Failed("...")
), then you need to inspect the returned value, not `fut.state`:
Copy code
inner = fut.result()  # this is a State returned by your task
if inner.is_failed():
    ...
elif inner.is_completed():
    ...
Important nuance: -
fut.state
is the orchestration state of the task run. It will usually be Completed if the task executed and returned a value—even if that value is a
Failed(...)
State object that you created. In that case,
fut.state.is_completed()
would be True, because the run succeeded in returning a value. - Returning Prefect State objects from tasks is generally not recommended; it’s easy to confuse “run state” with “returned value”. Prefer to: - Return a real boolean and check it:
Copy code
flag = fut.result()
    if not flag:
        ...
- Or fail the task by raising an exception (so
fut.state.is_failed()
becomes True and
fut.result()
raises):
Copy code
@task
    def do_thing(...):
        if bad_condition:
            raise RuntimeError("Failed to do xyz")
        return True
If you truly need to return a State and then read its payload:
Copy code
from prefect.states import get_state_result

inner = fut.result()  # a State
value = get_state_result(inner, raise_on_failure=False)
if inner.is_failed():
    # handle inner failure/message
elif inner.is_completed():
    # use value