Skip to content

Result Handling

.submit_requests() returns a ChainResults[T] — a list subclass that wraps the results of all chains in the batch. It has two properties: .success and .failed.

from cascade_cms.wrapper import Cascade
from cascade_cms.cmstypes import Asset

with Cascade(env) as cascade:
    results = cascade.operations.read("abc123").submit_requests(Asset)

print(len(results.success))   # assets that completed
print(len(results.failed))    # assets that hit an error

.success and .failed

Both return lists. .success is a list of the result type passed to .submit_requests(). .failed is a list of ChainFailure objects.

for asset in results.success:
    print(asset.path)          # typed as Asset

for failure in results.failed:
    print(failure.identifier)  # which asset failed
    print(failure.step_name)   # operation that failed ("read", "edit", …)
    print(failure.step)        # step index (int)
    print(failure.message)     # human-readable description
    print(failure.category)    # FailureCategory enum value

ChainFailure fields:

Field Type Description
chain_index int Position in the batch
identifier str Asset identifier
step int Index of the operation that failed
step_name str Name of the operation ("read", "edit", …)
category FailureCategory Error category (already computed)
error Exception Underlying exception
message str Summary string

Failure categories

ChainFailure.category already holds the FailureCategory value — use it directly. FailureCategory has four values:

from cascade_cms.utils.failures import FailureCategory

for failure in results.failed:
    if failure.category == FailureCategory.NETWORK:
        # transient — retry is reasonable
        ...
    elif failure.category == FailureCategory.CASCADE:
        # Cascade returned an error (bad identifier, permission denied, …)
        ...
    elif failure.category == FailureCategory.CALLBACK:
        # your edit callback raised an exception
        ...
    elif failure.category == FailureCategory.LIBRARY:
        # internal library error — file a bug
        ...
Category Cause
CASCADE Cascade CMS returned a failure response
NETWORK Request did not reach the server or timed out
CALLBACK An edit callback function raised an exception
LIBRARY Internal library error

Exit behavior

By default (exit_on_failure=True), Cascade exits the script non-zero when any chain fails. Code after the with block does not run:

with Cascade(env) as cascade:
    results = cascade.operations.read("abc123").submit_requests(Asset)

# Only runs when zero chains failed
print("All done.")

Pass exit_on_failure=False to keep the process alive regardless of failures — for example, inside an MCP server:

with Cascade(env, exit_on_failure=False) as cascade:
    results = cascade.operations.read("abc123").submit_requests(Asset)

if results.failed:
    log_failures(results.failed)

Upgrading from older versions

Prior to 3.8.0, result handling used isinstance checks against a CascadeError class. That pattern no longer works:

# Old pattern (pre-3.8.0) — do not use
result = wrapper.read(id)
if isinstance(result, CascadeError):
    print("failed")

# Current pattern (3.8.0+)
results = cascade.operations.read(id).submit_requests(Asset)
for failure in results.failed:
    print(f"[{failure.category}] {failure.message}")

See Version History for the full list of breaking changes between versions.