# Handle failures

!!! abstract “”

    How to create `NotCompleted` values, check their truthiness, inspect their attributes, and control propagation with `skip_not_completed=False`.

## `NotCompleted` FALSE type

A FALSE type is returned when a condition is not met. For example, below we create an app that selects 2 specific sequences from an alignment. Applying this to a data set where a “Mouse” sequence does not exist produces a FALSE type.

```python { linenums=“1” notest } import cogent3 as c3

aln = c3.get_dataset(“primate-brca1”) select_seqs = c3.get_app(“take_named_seqs”, “Mouse”, “Human”) result = select_seqs(aln) assert result == False print(result)

# NotCompleted(type=FAIL, origin=take_named_seqs, source=“brca1”, message=“named

# seq(s) {‘Mouse’} not in (‘FlyingLem’, ‘TreeShrew’, ‘Galago’, ‘HowlerMon’,

# ‘Rhesus’, ‘Orangutan’, ‘Gorilla’, ‘Chimpanzee’, ‘Human’)“)

    <!-- [[[end]]] -->

    ## Inspecting `NotCompleted` attributes

    The `NotCompleted` instance has attributes identifying what data failed:

    ```python { notest }
    result.source

Where the failure occurred:

`python { notest } result.origin`

And the reason for the failure:

`python { notest } result.message`

The `.type` attribute is the `NotCompletedType` enum value (e.g. `NotCompletedType.FALSE`, `NotCompletedType.ERROR`, or `NotCompletedType.BUG`).

## `NotCompleted` ERROR type

An ERROR type is returned if an unexpected condition occurs, such as an exception raised during execution. Here we illustrate this by trying to open a file with an incorrect path.

???- example “Example”

    ```python { linenums="1" notest }
    import cogent3 as c3

    reader = c3.get_app("load_aligned", moltype="dna")
    result = reader("primate_brca1.fasta")
    print(result)

    # NotCompleted(type=ERROR, origin=load_aligned, source="primate_brca1",
    # message="Traceback (most recent call last):   File
    # "/Users/gavin/repos/SciNexus/src/scinexus/composable.py", line 545, in __call__
    # result = self.main(val, *args, **kwargs) [...]
    ```

## Composed functions propagate `NotCompleted` results

If you have a composed function with multiple steps and a failure occurs, the resulting `NotCompleted` is returned without any of the subsequent steps being applied. For example, we make a composed app from both of the above apps:

???- example “Example”

    ```python { linenums="1" notest }
    import cogent3 as c3

    reader = c3.get_app("load_aligned", moltype="dna")
    select_seqs = c3.get_app("take_named_seqs", "Mouse", "Human")
    app = reader + select_seqs
    result = app("data/primate_brca1.fasta")
    print(result)

    # NotCompleted(type=FAIL, origin=take_named_seqs, source="primate_brca1",
    # message="named seq(s) {'Mouse'} not in ('FlyingLem', 'TreeShrew', 'Galago',
    # 'HowlerMon', 'Rhesus', 'Orangutan', 'Gorilla', 'Chimpanzee', 'Human')")
    ```

The failure originated in `select_seqs` (an instance of `take_named_seqs`), and `reader` ran successfully — but the `NotCompleted` propagated through the rest of the pipeline.

???- example “Example”

    ```python { linenums="1" notest }
    import cogent3 as c3

    reader = c3.get_app("load_aligned", moltype="dna")
    select_seqs = c3.get_app("take_named_seqs", "Mouse", "Human")
    app = reader + select_seqs
    result = app("primate_brca1.fasta")
    print(result)

    # NotCompleted(type=ERROR, origin=load_aligned, source="primate_brca1", [...]
    ```

Here the failure originated in `reader` (bad path), and `select_seqs` was never called.

## Creating `NotCompleted` in your own apps

You can return a `NotCompleted` from your own app to signal that a particular input cannot be processed:

```python { linenums=“1” notest } from scinexus import define_app, NotCompleted, NotCompletedType

@define_app def require_min_length(val: str, min_length: int = 10) -> str: if len(val) < min_length: return NotCompleted( NotCompletedType.FALSE, “require_min_length”, val, message=f”too short: {len(val)} < {min_length}“, ) return val

    <!-- [[[end]]] -->

    ## Receiving `NotCompleted` with `skip_not_completed=False`

    By default, apps skip `NotCompleted` inputs — they propagate without calling `main()`. If your app needs to see `NotCompleted` values (e.g. a writer that records failures), set `skip_not_completed=False`:

    <!-- [[[cog
    from cog_utils import exec_codeblock

    src = \
    """
    from scinexus import define_app, NotCompleted

    @define_app(skip_not_completed=False)
    def log_failures(val: str) -> str:
        if isinstance(val, NotCompleted):
            print(f"Failure: {val.message}")
            return val
        return val
    """
    exec_codeblock(src=src)
      ]]] -->
    ```python { linenums="1" notest }
    from scinexus import define_app, NotCompleted

    @define_app(skip_not_completed=False)
    def log_failures(val: str) -> str:
        if isinstance(val, NotCompleted):
            print(f"Failure: {val.message}")
            return val
        return val