<h3 dir="auto">First check</h3>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I added a very descriptive title to this issue.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I used the GitHub search to find a similar issue and didn't find it.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I searched the FastAPI documentation, with the integrated search.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I already searched in Google "How to X in FastAPI" and didn't find any information.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I already read and followed all the tutorial in the docs and didn't find an answer.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I already checked if it is not related to FastAPI but to <a href="https://github.com/samuelcolvin/pydantic">Pydantic</a>.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I already checked if it is not related to FastAPI but to <a href="https://github.com/swagger-api/swagger-ui">Swagger UI</a>.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I already checked if it is not related to FastAPI but to <a href="https://github.com/Redocly/redoc">ReDoc</a>.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> After submitting this, I commit to one of:
<ul dir="auto">
<li>Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there.</li>
<li>I already hit the "watch" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future.</li>
<li>Implement a Pull Request for a confirmed bug.</li>
</ul>
</li>
</ul>
<h3 dir="auto">Example</h3>
<p dir="auto">Here's a self-contained, <a href="https://stackoverflow.com/help/minimal-reproducible-example" rel="nofollow">minimal, reproducible, example</a> with my use case:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="from fastapi import FastAPI, Request, Depends
from fastapi.responses import JSONResponse
from starlette import status


class CustomException(Exception):
    pass


async def some_dep():
    print(&quot;inside dep&quot;)
    try:
        yield 123
    except Exception as e:
        print(&quot;exception occurred&quot;)  # it disappears with custom handler
    finally:
        print(&quot;finally in dep&quot;)


def create_app() -&gt; FastAPI:
    app = FastAPI()

    @app.on_event(&quot;startup&quot;)
    async def startup():
        print(&quot;startup action&quot;)

    @app.on_event(&quot;shutdown&quot;)
    async def shutdown():
        print(&quot;shutdown action&quot;)

    # when commenting line below &quot;exception occurred&quot; line appears on post request
    install_exception_handlers(app)

    @app.post(&quot;/qwe&quot;)
    async def qwe(a: int = Depends(some_dep)):
        print(a)
        raise CustomException

    return app


def install_exception_handlers(app: FastAPI):
    @app.exception_handler(CustomException)
    async def postgres_error_handler(_: Request, __: CustomException) -&gt; JSONResponse:
        return JSONResponse(
            dict(response=&quot;this is json response&quot;),
            status_code=status.HTTP_400_BAD_REQUEST,
        )"><pre class="notranslate"><span class="pl-k">from</span> <span class="pl-s1">fastapi</span> <span class="pl-k">import</span> <span class="pl-v">FastAPI</span>, <span class="pl-v">Request</span>, <span class="pl-v">Depends</span>
<span class="pl-k">from</span> <span class="pl-s1">fastapi</span>.<span class="pl-s1">responses</span> <span class="pl-k">import</span> <span class="pl-v">JSONResponse</span>
<span class="pl-k">from</span> <span class="pl-s1">starlette</span> <span class="pl-k">import</span> <span class="pl-s1">status</span>


<span class="pl-k">class</span> <span class="pl-v">CustomException</span>(<span class="pl-v">Exception</span>):
    <span class="pl-k">pass</span>


<span class="pl-k">async</span> <span class="pl-k">def</span> <span class="pl-en">some_dep</span>():
    <span class="pl-en">print</span>(<span class="pl-s">"inside dep"</span>)
    <span class="pl-k">try</span>:
        <span class="pl-k">yield</span> <span class="pl-c1">123</span>
    <span class="pl-k">except</span> <span class="pl-v">Exception</span> <span class="pl-k">as</span> <span class="pl-s1">e</span>:
        <span class="pl-en">print</span>(<span class="pl-s">"exception occurred"</span>)  <span class="pl-c"># it disappears with custom handler</span>
    <span class="pl-k">finally</span>:
        <span class="pl-en">print</span>(<span class="pl-s">"finally in dep"</span>)


<span class="pl-k">def</span> <span class="pl-en">create_app</span>() <span class="pl-c1">-&gt;</span> <span class="pl-v">FastAPI</span>:
    <span class="pl-s1">app</span> <span class="pl-c1">=</span> <span class="pl-v">FastAPI</span>()

    <span class="pl-en">@<span class="pl-s1">app</span>.<span class="pl-en">on_event</span>(<span class="pl-s">"startup"</span>)</span>
    <span class="pl-k">async</span> <span class="pl-k">def</span> <span class="pl-en">startup</span>():
        <span class="pl-en">print</span>(<span class="pl-s">"startup action"</span>)

    <span class="pl-en">@<span class="pl-s1">app</span>.<span class="pl-en">on_event</span>(<span class="pl-s">"shutdown"</span>)</span>
    <span class="pl-k">async</span> <span class="pl-k">def</span> <span class="pl-en">shutdown</span>():
        <span class="pl-en">print</span>(<span class="pl-s">"shutdown action"</span>)

    <span class="pl-c"># when commenting line below "exception occurred" line appears on post request</span>
    <span class="pl-en">install_exception_handlers</span>(<span class="pl-s1">app</span>)

    <span class="pl-en">@<span class="pl-s1">app</span>.<span class="pl-en">post</span>(<span class="pl-s">"/qwe"</span>)</span>
    <span class="pl-k">async</span> <span class="pl-k">def</span> <span class="pl-en">qwe</span>(<span class="pl-s1">a</span>: <span class="pl-s1">int</span> <span class="pl-c1">=</span> <span class="pl-v">Depends</span>(<span class="pl-s1">some_dep</span>)):
        <span class="pl-en">print</span>(<span class="pl-s1">a</span>)
        <span class="pl-k">raise</span> <span class="pl-v">CustomException</span>

    <span class="pl-k">return</span> <span class="pl-s1">app</span>


<span class="pl-k">def</span> <span class="pl-en">install_exception_handlers</span>(<span class="pl-s1">app</span>: <span class="pl-v">FastAPI</span>):
    <span class="pl-en">@<span class="pl-s1">app</span>.<span class="pl-en">exception_handler</span>(<span class="pl-v">CustomException</span>)</span>
    <span class="pl-k">async</span> <span class="pl-k">def</span> <span class="pl-en">postgres_error_handler</span>(<span class="pl-s1">_</span>: <span class="pl-v">Request</span>, <span class="pl-s1">__</span>: <span class="pl-v">CustomException</span>) <span class="pl-c1">-&gt;</span> <span class="pl-v">JSONResponse</span>:
        <span class="pl-k">return</span> <span class="pl-v">JSONResponse</span>(
            <span class="pl-en">dict</span>(<span class="pl-s1">response</span><span class="pl-c1">=</span><span class="pl-s">"this is json response"</span>),
            <span class="pl-s1">status_code</span><span class="pl-c1">=</span><span class="pl-s1">status</span>.<span class="pl-v">HTTP_400_BAD_REQUEST</span>,
        )</pre></div>
<h3 dir="auto">Description</h3>

<ul dir="auto">
<li>Run FastAPI application</li>
<li>Call <code class="notranslate">curl -X POST http://127.0.0.1:8000/qwe</code> in bash</li>
<li>Got output:
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="inside dep
123
INFO:     127.0.0.1:57400 - &quot;POST /qwe HTTP/1.1&quot; 400 Bad Request
finally in dep"><pre class="notranslate"><code class="notranslate">inside dep
123
INFO:     127.0.0.1:57400 - "POST /qwe HTTP/1.1" 400 Bad Request
finally in dep
</code></pre></div>
</li>
<li>Comment line <code class="notranslate">install_exception_handlers(app)</code></li>
<li>Reload app</li>
<li>Call <code class="notranslate">curl -X POST http://127.0.0.1:8000/qwe</code> in bash</li>
<li>Got output (output has <code class="notranslate">exception occurred</code> line that should also be with custom exception handler):
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="inside dep
123
INFO:     127.0.0.1:57414 - &quot;POST /qwe HTTP/1.1&quot; 500 Internal Server Error
exception occurred
finally in dep"><pre class="notranslate"><code class="notranslate">inside dep
123
INFO:     127.0.0.1:57414 - "POST /qwe HTTP/1.1" 500 Internal Server Error
exception occurred
finally in dep
</code></pre></div>
</li>
</ul>
<h3 dir="auto">Environment</h3>
<ul dir="auto">
<li>
<p dir="auto">OS: <code class="notranslate">Linux artslob-laptop 5.4.0-48-generic #52~18.04.1-Ubuntu SMP Thu Sep 10 12:50:22 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux</code>:</p>
</li>
<li>
<p dir="auto">Dependencies:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="$pip list
Package            Version
------------------ -------
attrs              20.2.0
click              7.1.2
fastapi            0.61.1
h11                0.11.0
importlib-metadata 2.0.0
iniconfig          1.0.1
packaging          20.4
pip                20.2.3
pluggy             0.13.1
py                 1.9.0
pydantic           1.6.1
pyparsing          2.4.7
pytest             6.1.1
pytest-asyncio     0.14.0
setuptools         50.3.0
six                1.15.0
starlette          0.13.6
toml               0.10.1
typing-extensions  3.7.4.3
uvicorn            0.12.1
zipp               3.3.0"><pre class="notranslate"><code class="notranslate">$pip list
Package            Version
------------------ -------
attrs              20.2.0
click              7.1.2
fastapi            0.61.1
h11                0.11.0
importlib-metadata 2.0.0
iniconfig          1.0.1
packaging          20.4
pip                20.2.3
pluggy             0.13.1
py                 1.9.0
pydantic           1.6.1
pyparsing          2.4.7
pytest             6.1.1
pytest-asyncio     0.14.0
setuptools         50.3.0
six                1.15.0
starlette          0.13.6
toml               0.10.1
typing-extensions  3.7.4.3
uvicorn            0.12.1
zipp               3.3.0
</code></pre></div>
</li>
<li>
<p dir="auto">Python version: 3.7.4</p>
</li>
</ul>
<h3 dir="auto">Additional context</h3>
<p dir="auto">Repo with code: <a href="https://github.com/artslob/check-custom-handler-fastapi">https://github.com/artslob/check-custom-handler-fastapi</a>.</p>
<p dir="auto">So what we see here is that custom exception handler does not provide context about exception to yielding code in FastAPI dependecy. Its pretty ctitical, because if dependency is database transaction then it can result in false negative session commit (when actually commit is not desired).</p>
<h3 dir="auto">Describe the bug</h3>
<p dir="auto">HTTP exceptions are not <del>raised</del> propagated inside a dependency which encapsulates the <code class="notranslate">yield</code> in a try except statement.<br>
Only custom exceptions are <del>raised</del> propagated if I understand correctly.</p>
<h3 dir="auto">To Reproduce</h3>
<ol dir="auto">
<li>
<p dir="auto">Create a main.py with:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="from fastapi import Depends, FastAPI, HTTPException

app = FastAPI()


def new_db_session():
    try:
        yield

    except Exception:
        print(&quot;rollback&quot;)

    else:
        print(&quot;commit&quot;)

    finally:
        print(&quot;close&quot;)


@app.get(&quot;/exception&quot;)
def get_exception(db=Depends(new_db_session)):
    raise Exception()


@app.get(&quot;/http_exception&quot;)
def get_exception(db=Depends(new_db_session)):
    raise HTTPException(status_code=400, detail=&quot;invalid request&quot;)"><pre class="notranslate"><span class="pl-k">from</span> <span class="pl-s1">fastapi</span> <span class="pl-k">import</span> <span class="pl-v">Depends</span>, <span class="pl-v">FastAPI</span>, <span class="pl-v">HTTPException</span>

<span class="pl-s1">app</span> <span class="pl-c1">=</span> <span class="pl-v">FastAPI</span>()


<span class="pl-k">def</span> <span class="pl-en">new_db_session</span>():
    <span class="pl-k">try</span>:
        <span class="pl-k">yield</span>

    <span class="pl-k">except</span> <span class="pl-v">Exception</span>:
        <span class="pl-en">print</span>(<span class="pl-s">"rollback"</span>)

    <span class="pl-k">else</span>:
        <span class="pl-en">print</span>(<span class="pl-s">"commit"</span>)

    <span class="pl-k">finally</span>:
        <span class="pl-en">print</span>(<span class="pl-s">"close"</span>)


<span class="pl-en">@<span class="pl-s1">app</span>.<span class="pl-en">get</span>(<span class="pl-s">"/exception"</span>)</span>
<span class="pl-k">def</span> <span class="pl-en">get_exception</span>(<span class="pl-s1">db</span><span class="pl-c1">=</span><span class="pl-v">Depends</span>(<span class="pl-s1">new_db_session</span>)):
    <span class="pl-k">raise</span> <span class="pl-v">Exception</span>()


<span class="pl-en">@<span class="pl-s1">app</span>.<span class="pl-en">get</span>(<span class="pl-s">"/http_exception"</span>)</span>
<span class="pl-k">def</span> <span class="pl-en">get_exception</span>(<span class="pl-s1">db</span><span class="pl-c1">=</span><span class="pl-v">Depends</span>(<span class="pl-s1">new_db_session</span>)):
    <span class="pl-k">raise</span> <span class="pl-v">HTTPException</span>(<span class="pl-s1">status_code</span><span class="pl-c1">=</span><span class="pl-c1">400</span>, <span class="pl-s1">detail</span><span class="pl-c1">=</span><span class="pl-s">"invalid request"</span>)</pre></div>
</li>
<li>
<p dir="auto">run app using <code class="notranslate">uvicorn main:app</code></p>
</li>
<li>
<p dir="auto">curl <code class="notranslate">http://127.0.0.1:8000/exception</code>; app prints:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="INFO:     127.0.0.1:50069 - &quot;GET /exception HTTP/1.1&quot; 500 Internal Server Error
rollback
close"><pre class="notranslate"><code class="notranslate">INFO:     127.0.0.1:50069 - "GET /exception HTTP/1.1" 500 Internal Server Error
rollback
close
</code></pre></div>
</li>
<li>
<p dir="auto">curl <code class="notranslate">http://127.0.0.1:8000/http_exception</code>; app prints:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="INFO:     127.0.0.1:50072 - &quot;GET /http_exception HTTP/1.1&quot; 400 Bad Request
commit
close"><pre class="notranslate"><code class="notranslate">INFO:     127.0.0.1:50072 - "GET /http_exception HTTP/1.1" 400 Bad Request
commit
close
</code></pre></div>
</li>
</ol>
<h3 dir="auto">Expected behavior</h3>
<p dir="auto">HTTP Exception should be <del>raised</del> propagated inside the dependency try except statement.</p>
<h3 dir="auto">Environment</h3>
<ul dir="auto">
<li><code class="notranslate">OS: Darwin Kernel Version 19.0.0: Thu Oct 17 16:17:15 PDT 2019; root:xnu-6153.41.3~29/RELEASE_X86_64 x86_64 i386 MacBookPro13,1 Darwin</code></li>
<li>FastAPI Version: <code class="notranslate">0.46.0</code></li>
<li>Python version: Python <code class="notranslate">3.7.3</code></li>
</ul>
<h3 dir="auto">Additional context</h3>
<ul dir="auto">
<li><a href="https://github.com/tiangolo/fastapi/595">PR: Dependencies with yield (used as context managers)</a></li>
<li>From <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/dmontagu/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/dmontagu">@dmontagu</a> in <a href="https://github.com/tiangolo/fastapi/pull/570#issuecomment-538680343" data-hovercard-type="pull_request" data-hovercard-url="/tiangolo/fastapi/pull/570/hovercard">#570</a>:
<blockquote>
<p dir="auto"><a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/cjw296/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/cjw296">@cjw296</a> As implemented, it would require some care to ensure teardown was done in a guaranteed order. I think it would currently amount to constructing a consistent "teardown" dependency. But I think in most cases, you would be able to just build a single dependency that sets everything up in order, and tears it down in order, and then to build other dependencies on top of that. For example, handling your use case:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="def db_contextmanager():
    conn = connect_to_db()
    t = conn.transaction()
    try:
         yield conn, t
        t.commit()
    except:
        t.rollback()
     conn.close()

def get_connection(conn_t = Depends(db_contextmanager)):
    conn, t = conn_t
    return conn

def get_transaction(conn_t = Depends(db_contextmanager)):
    conn, t = conn_t
    return t

def endpoint(conn = Depends(get_connection)):
    # Do something with the connection
    pass"><pre class="notranslate"><span class="pl-k">def</span> <span class="pl-s1">db_contextmanager</span>():
    <span class="pl-s1">conn</span> <span class="pl-c1">=</span> <span class="pl-en">connect_to_db</span>()
    <span class="pl-s1">t</span> <span class="pl-c1">=</span> <span class="pl-s1">conn</span>.<span class="pl-en">transaction</span>()
    <span class="pl-k">try</span>:
         <span class="pl-k">yield</span> <span class="pl-s1">conn</span>, <span class="pl-s1">t</span>
        <span class="pl-s1">t</span>.<span class="pl-en">commit</span>()
    <span class="pl-s1">except</span>:
        <span class="pl-s1">t</span>.<span class="pl-en">rollback</span>()
     <span class="pl-s1">conn</span>.<span class="pl-en">close</span>()

<span class="pl-k">def</span> <span class="pl-en">get_connection</span>(<span class="pl-s1">conn_t</span> <span class="pl-c1">=</span> <span class="pl-v">Depends</span>(<span class="pl-s1">db_contextmanager</span>)):
    <span class="pl-s1">conn</span>, <span class="pl-s1">t</span> <span class="pl-c1">=</span> <span class="pl-s1">conn_t</span>
    <span class="pl-k">return</span> <span class="pl-s1">conn</span>

<span class="pl-k">def</span> <span class="pl-en">get_transaction</span>(<span class="pl-s1">conn_t</span> <span class="pl-c1">=</span> <span class="pl-v">Depends</span>(<span class="pl-s1">db_contextmanager</span>)):
    <span class="pl-s1">conn</span>, <span class="pl-s1">t</span> <span class="pl-c1">=</span> <span class="pl-s1">conn_t</span>
    <span class="pl-k">return</span> <span class="pl-s1">t</span>

<span class="pl-k">def</span> <span class="pl-en">endpoint</span>(<span class="pl-s1">conn</span> <span class="pl-c1">=</span> <span class="pl-v">Depends</span>(<span class="pl-s1">get_connection</span>)):
    <span class="pl-c"># Do something with the connection</span>
    <span class="pl-k">pass</span></pre></div>
</blockquote>
</li>
</ul>