def check_execution(executor, nb, raise_fast):
    """Check that all code cells with source have been executed without error."""
    error = None
    for cell in nb.get("cells", []):

        # Only check code cells
        if cell["cell_type"] != "code":
            continue

        if cell["source"] and cell["execution_count"] is None:
            error = "Notebook has unexecuted code cell(s)."
            if raise_fast:
                raise RuntimeError(error)
            break
        else:
            for output in cell["outputs"]:
                if output["output_type"] == "error":
                    if output["ename"] in executor.allow_error_names:
                        continue
                    error = "\n".join(output["traceback"])
                    if raise_fast:
                        raise RuntimeError("\n" + error)
                    break

    return error