Dmytro Stelmakh
05/19/2026, 10:38 AMMarvin
05/19/2026, 10:38 AMMarvin
05/19/2026, 10:40 AMpersist_result controls whether a task's return value is stored as a Prefect result.
Short version:
* persist_result=True → Prefect stores the task result in result storage and only sends small metadata to the Prefect API
* persist_result=False → Prefect does not persist the result
* default None → Prefect decides automatically based on config/features like caching/result storage
So for your 413 question:
If the 413 is coming from Prefect trying to send a large task result/state payload to the Prefect API, then yes, result persistence can help.
*If the 413 is coming from your task making an HTTP request to some external service with a huge JSON body, persist_result will not fix that.*
A useful distinction:
1. Task input/output data inside Prefect orchestration
* persist_result can matter here
2. HTTP calls your task makes to another API
* persist_result does not change that request body at all
Example:
python
from prefect import task
@task(persist_result=True)
def make_big_object():
return {"huge": "...large json..."}
With persistence enabled, Prefect stores that result in result storage and sends metadata instead of the whole object through the API/state payload path.
But if your task does this:
python
@task
def send_big_json(payload):
<http://requests.post|requests.post>("<https://example.com/endpoint>", json=payload)
and <http://requests.post|requests.post>(...) gets a 413 Payload Too Large, then persist_result is unrelated. The remote server is rejecting the body you are sending.
Likely scenarios:
* 413 from Prefect API / orchestration path:
* large result objects
* large parameters/state payloads
* persist_result=True may help
* 413 from your target HTTP service:
* huge JSON request body
* you need to reduce/chunk/compress/store externally instead
If you want, I can help you determine which side is returning the 413 and suggest the right fix. For example, paste:
* the full error message/stack trace
* whether the large JSON is a task return value or an HTTP request body sent by the taskDmytro Stelmakh
05/19/2026, 11:10 AMMarvin
05/19/2026, 11:10 AMMarvin
05/19/2026, 11:12 AM413.
That means:
* persist_result on the subflow does not prevent the large parameter from being sent
* persist_result helps with results, not with a raw large parameter being passed into a subflow call
So this will still be risky:
python
@flow
def parent():
big_json = {...very large...}
child(big_json) # may still hit 413
Because the large object is being passed as a subflow parameter.
What can work without abandoning subflows?
Option 1: store the large data first, then pass a reference to the subflow
This is the cleanest approach.
python
from prefect import flow, task
@task(persist_result=True)
def produce_big_json():
return {"very": "large payload ..."}
@flow
def child(data_ref):
data = data_ref
# use data here
return len(str(data))
@flow
def parent():
big_json = produce_big_json()
return child(big_json)
The key idea is:
* create the big payload in a task
* let Prefect persist that task result
* pass the task future / persisted result reference into the subflow instead of a raw giant Python object
That usually avoids sending the full payload in the parent→subflow API request.
Option 2: write the payload to external storage and pass only a URI/key
For very large data, this is often the most robust pattern.
python
from prefect import flow, task
@task
def write_payload():
# write to S3 / GCS / local shared storage / DB
return "<s3://my-bucket/path/to/payload.json>"
@flow
def child(payload_uri):
# load from storage here
return payload_uri
@flow
def parent():
uri = write_payload()
return child(uri)
Then the flow/subflow boundary only carries something small like a string.
Option 3: use tasks for the heavy data boundary, keep flows for orchestration
You do not need to convert the whole design to tasks-only.
A common pattern is:
* flows orchestrate
* tasks produce/store/load large data
* subflows receive lightweight references or futures
That gives you the organizational benefits of subflows without forcing huge payloads through the API.
What probably will not help by itself
python
@flow(persist_result=True)
def child(big_json):
...
This persists the child flow result, but the problem happens before the child starts — while sending big_json as the subflow parameter.
Recommended approach
If your issue is specifically the parent flow handing a huge JSON blob to a subflow, I’d recommend:
1. move creation/loading of the large blob into a task
2. enable result persistence for that task
3. pass the task result reference or an external storage key into the subflow
4. keep the subflow structure if that’s important for your design
So yes: you can usually keep subflows, but you should avoid passing giant raw objects directly across the flow→subflow boundary.
If you want, I can sketch the exact refactor pattern for your current code:
* current parent flow
* current subflow signature
* where the large JSON is created/loadedsent