fix(api): stop otel turning every 405 into a 500 (unblocks 5 PRs) - #564

Merged
Jose-Gael-Cruz-Lopez merged 1 commit into
mainfrom
fix/otel-fastapi-405-500
Aug 19, 2026
Merged

fix(api): stop otel turning every 405 into a 500 (unblocks 5 PRs)#564
Jose-Gael-Cruz-Lopez merged 1 commit into
mainfrom
fix/otel-fastapi-405-500

Conversation

@Jose-Gael-Cruz-Lopez

Copy link
Copy Markdown
Member

Why this is separate

Backend (pytest) has been red on main since the FastAPI 0.138 lock, on one test:

FAILED tests/test_quiz_preflight_a.py::TestQuizErrorEnvelope::test_method_not_allowed_gets_generic_code
AttributeError: '_IncludedRouter' object has no attribute 'path'
opentelemetry/instrumentation/fastapi/__init__.py:495

This is not test-only. otel's _get_route_details guards its FULL-match .path read with except AttributeError, but its PARTIAL-match branch does not — and a PARTIAL match is exactly a wrong-method request. The error escapes the middleware, so every 405 returns 500. Staging and production install the same lock, so that is live behaviour today.

There is nothing to upgrade to: the unguarded line is present in every released opentelemetry-instrumentation-fastapi through 0.65b0. services/otel_fastapi_compat.py wraps the resolver, absorbing only AttributeError and falling back to scope["path"] — which is otel's own FULL-branch fallback.

Why now

This one failure is blocking the CI of five open PRs, none of which touch routing or quiz:

PR
#562fix(tutor): stop the tutor repeating itself
#536fix(learn): add a concept back after deleting it
#535feat(landing): port the v5 marketing landing
#512feat(academics): per-section Fall 2026 offerings
#507feat(documents): file-level dedup

Their pull_request runs check out a merge of head + base, so landing this on main turns all five green without touching their branches.

Relationship to #563

The three files here are lifted verbatim from #563, which diagnosed the bug and already carries the fix. backend/main.py is byte-identical to that branch's version, so #563 still auto-merges cleanly after this lands — both sides hold the same content. #563 keeps the credit for the diagnosis; this just unblocks the queue ahead of it.

Verification

  • ruff check . clean
  • Full hermetic suite: 1970 passed, 56 skipped
  • test_otel_fastapi_compat.py + test_quiz_preflight_a.py: 27 passed

`Backend (pytest)` has been red on main since the FastAPI 0.138 lock, on
test_quiz_preflight_a.py::TestQuizErrorEnvelope::test_method_not_allowed_gets_generic_code:
AttributeError: '_IncludedRouter' object has no attribute 'path'
Not test-only. otel's _get_route_details guards its FULL-match `.path` read
with `except AttributeError` but its PARTIAL-match branch does not — and a
PARTIAL match is exactly a wrong-method request. So the error escapes the
middleware and every 405 returns 500. Staging and prod install the same lock,
so that is live behaviour.
Nothing to upgrade to: the unguarded line is in every released
opentelemetry-instrumentation-fastapi through 0.65b0. services/otel_fastapi_compat.py
wraps the resolver, absorbing only AttributeError and falling back to
scope["path"] — otel's own FULL-branch fallback.
Lifted verbatim from #563 so that PR still auto-merges after this lands; it
blocks five other open PRs whose CI runs against a merge with main.
@coderabbitai

Copy link
Copy Markdown

Warning

Review limit reached

@Jose-Gael-Cruz-Lopez, you've reached your PR review limit, so we couldn't start this review.

Next review available in:52 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 02aec938-72dc-4825-9aff-5b58245d5dbd

📥 Commits

Reviewing files that changed from the base of the PR and between 4f5a7f9 and 9bba412.

📒 Files selected for processing (3)
  • backend/main.py
  • backend/services/otel_fastapi_compat.py
  • backend/tests/test_otel_fastapi_compat.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@supabase

supabaseBot commented Aug 19, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project ybgqdonkoqftwrmweuyv because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopez merged commit 38905c6 into mainAug 19, 2026
7 checks passed
@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopez deleted the fix/otel-fastapi-405-500 branch August 19, 2026 20:41
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Jose-Gael-Cruz-Lopez
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(api): stop otel turning every 405 into a 500 (unblocks 5 PRs) - #564

Merged
Jose-Gael-Cruz-Lopez merged 1 commit into
mainfrom
fix/otel-fastapi-405-500
Aug 19, 2026
Merged

fix(api): stop otel turning every 405 into a 500 (unblocks 5 PRs)#564
Jose-Gael-Cruz-Lopez merged 1 commit into
mainfrom
fix/otel-fastapi-405-500

Conversation

@Jose-Gael-Cruz-Lopez

Copy link
Copy Markdown
Member

Why this is separate

Backend (pytest) has been red on main since the FastAPI 0.138 lock, on one test:

FAILED tests/test_quiz_preflight_a.py::TestQuizErrorEnvelope::test_method_not_allowed_gets_generic_code
AttributeError: '_IncludedRouter' object has no attribute 'path'
opentelemetry/instrumentation/fastapi/__init__.py:495

This is not test-only. otel's _get_route_details guards its FULL-match .path read with except AttributeError, but its PARTIAL-match branch does not — and a PARTIAL match is exactly a wrong-method request. The error escapes the middleware, so every 405 returns 500. Staging and production install the same lock, so that is live behaviour today.

There is nothing to upgrade to: the unguarded line is present in every released opentelemetry-instrumentation-fastapi through 0.65b0. services/otel_fastapi_compat.py wraps the resolver, absorbing only AttributeError and falling back to scope["path"] — which is otel's own FULL-branch fallback.

Why now

This one failure is blocking the CI of five open PRs, none of which touch routing or quiz:

PR
#562fix(tutor): stop the tutor repeating itself
#536fix(learn): add a concept back after deleting it
#535feat(landing): port the v5 marketing landing
#512feat(academics): per-section Fall 2026 offerings
#507feat(documents): file-level dedup

Their pull_request runs check out a merge of head + base, so landing this on main turns all five green without touching their branches.

Relationship to #563

The three files here are lifted verbatim from #563, which diagnosed the bug and already carries the fix. backend/main.py is byte-identical to that branch's version, so #563 still auto-merges cleanly after this lands — both sides hold the same content. #563 keeps the credit for the diagnosis; this just unblocks the queue ahead of it.

Verification

  • ruff check . clean
  • Full hermetic suite: 1970 passed, 56 skipped
  • test_otel_fastapi_compat.py + test_quiz_preflight_a.py: 27 passed

`Backend (pytest)` has been red on main since the FastAPI 0.138 lock, on
test_quiz_preflight_a.py::TestQuizErrorEnvelope::test_method_not_allowed_gets_generic_code:
AttributeError: '_IncludedRouter' object has no attribute 'path'
Not test-only. otel's _get_route_details guards its FULL-match `.path` read
with `except AttributeError` but its PARTIAL-match branch does not — and a
PARTIAL match is exactly a wrong-method request. So the error escapes the
middleware and every 405 returns 500. Staging and prod install the same lock,
so that is live behaviour.
Nothing to upgrade to: the unguarded line is in every released
opentelemetry-instrumentation-fastapi through 0.65b0. services/otel_fastapi_compat.py
wraps the resolver, absorbing only AttributeError and falling back to
scope["path"] — otel's own FULL-branch fallback.
Lifted verbatim from #563 so that PR still auto-merges after this lands; it
blocks five other open PRs whose CI runs against a merge with main.
@coderabbitai

Copy link
Copy Markdown

Warning

Review limit reached

@Jose-Gael-Cruz-Lopez, you've reached your PR review limit, so we couldn't start this review.

Next review available in:52 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 02aec938-72dc-4825-9aff-5b58245d5dbd

📥 Commits

Reviewing files that changed from the base of the PR and between 4f5a7f9 and 9bba412.

📒 Files selected for processing (3)
  • backend/main.py
  • backend/services/otel_fastapi_compat.py
  • backend/tests/test_otel_fastapi_compat.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@supabase

supabaseBot commented Aug 19, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project ybgqdonkoqftwrmweuyv because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopez merged commit 38905c6 into mainAug 19, 2026
7 checks passed
@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopez deleted the fix/otel-fastapi-405-500 branch August 19, 2026 20:41
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Jose-Gael-Cruz-Lopez
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(api): stop otel turning every 405 into a 500 (unblocks 5 PRs) - #564

Merged
Jose-Gael-Cruz-Lopez merged 1 commit into
mainfrom
fix/otel-fastapi-405-500
Aug 19, 2026
Merged

fix(api): stop otel turning every 405 into a 500 (unblocks 5 PRs)#564
Jose-Gael-Cruz-Lopez merged 1 commit into
mainfrom
fix/otel-fastapi-405-500

Conversation

@Jose-Gael-Cruz-Lopez

Copy link
Copy Markdown
Member

Why this is separate

Backend (pytest) has been red on main since the FastAPI 0.138 lock, on one test:

FAILED tests/test_quiz_preflight_a.py::TestQuizErrorEnvelope::test_method_not_allowed_gets_generic_code
AttributeError: '_IncludedRouter' object has no attribute 'path'
opentelemetry/instrumentation/fastapi/__init__.py:495

This is not test-only. otel's _get_route_details guards its FULL-match .path read with except AttributeError, but its PARTIAL-match branch does not — and a PARTIAL match is exactly a wrong-method request. The error escapes the middleware, so every 405 returns 500. Staging and production install the same lock, so that is live behaviour today.

There is nothing to upgrade to: the unguarded line is present in every released opentelemetry-instrumentation-fastapi through 0.65b0. services/otel_fastapi_compat.py wraps the resolver, absorbing only AttributeError and falling back to scope["path"] — which is otel's own FULL-branch fallback.

Why now

This one failure is blocking the CI of five open PRs, none of which touch routing or quiz:

PR
#562fix(tutor): stop the tutor repeating itself
#536fix(learn): add a concept back after deleting it
#535feat(landing): port the v5 marketing landing
#512feat(academics): per-section Fall 2026 offerings
#507feat(documents): file-level dedup

Their pull_request runs check out a merge of head + base, so landing this on main turns all five green without touching their branches.

Relationship to #563

The three files here are lifted verbatim from #563, which diagnosed the bug and already carries the fix. backend/main.py is byte-identical to that branch's version, so #563 still auto-merges cleanly after this lands — both sides hold the same content. #563 keeps the credit for the diagnosis; this just unblocks the queue ahead of it.

Verification

  • ruff check . clean
  • Full hermetic suite: 1970 passed, 56 skipped
  • test_otel_fastapi_compat.py + test_quiz_preflight_a.py: 27 passed

`Backend (pytest)` has been red on main since the FastAPI 0.138 lock, on
test_quiz_preflight_a.py::TestQuizErrorEnvelope::test_method_not_allowed_gets_generic_code:
AttributeError: '_IncludedRouter' object has no attribute 'path'
Not test-only. otel's _get_route_details guards its FULL-match `.path` read
with `except AttributeError` but its PARTIAL-match branch does not — and a
PARTIAL match is exactly a wrong-method request. So the error escapes the
middleware and every 405 returns 500. Staging and prod install the same lock,
so that is live behaviour.
Nothing to upgrade to: the unguarded line is in every released
opentelemetry-instrumentation-fastapi through 0.65b0. services/otel_fastapi_compat.py
wraps the resolver, absorbing only AttributeError and falling back to
scope["path"] — otel's own FULL-branch fallback.
Lifted verbatim from #563 so that PR still auto-merges after this lands; it
blocks five other open PRs whose CI runs against a merge with main.
@coderabbitai

Copy link
Copy Markdown

Warning

Review limit reached

@Jose-Gael-Cruz-Lopez, you've reached your PR review limit, so we couldn't start this review.

Next review available in:52 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 02aec938-72dc-4825-9aff-5b58245d5dbd

📥 Commits

Reviewing files that changed from the base of the PR and between 4f5a7f9 and 9bba412.

📒 Files selected for processing (3)
  • backend/main.py
  • backend/services/otel_fastapi_compat.py
  • backend/tests/test_otel_fastapi_compat.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@supabase

supabaseBot commented Aug 19, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project ybgqdonkoqftwrmweuyv because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopez merged commit 38905c6 into mainAug 19, 2026
7 checks passed
@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopez deleted the fix/otel-fastapi-405-500 branch August 19, 2026 20:41
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Jose-Gael-Cruz-Lopez
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(api): stop otel turning every 405 into a 500 (unblocks 5 PRs) - #564

Merged
Jose-Gael-Cruz-Lopez merged 1 commit into
mainfrom
fix/otel-fastapi-405-500
Aug 19, 2026
Merged

fix(api): stop otel turning every 405 into a 500 (unblocks 5 PRs)#564
Jose-Gael-Cruz-Lopez merged 1 commit into
mainfrom
fix/otel-fastapi-405-500

Conversation

@Jose-Gael-Cruz-Lopez

Copy link
Copy Markdown
Member

Why this is separate

Backend (pytest) has been red on main since the FastAPI 0.138 lock, on one test:

FAILED tests/test_quiz_preflight_a.py::TestQuizErrorEnvelope::test_method_not_allowed_gets_generic_code
AttributeError: '_IncludedRouter' object has no attribute 'path'
opentelemetry/instrumentation/fastapi/__init__.py:495

This is not test-only. otel's _get_route_details guards its FULL-match .path read with except AttributeError, but its PARTIAL-match branch does not — and a PARTIAL match is exactly a wrong-method request. The error escapes the middleware, so every 405 returns 500. Staging and production install the same lock, so that is live behaviour today.

There is nothing to upgrade to: the unguarded line is present in every released opentelemetry-instrumentation-fastapi through 0.65b0. services/otel_fastapi_compat.py wraps the resolver, absorbing only AttributeError and falling back to scope["path"] — which is otel's own FULL-branch fallback.

Why now

This one failure is blocking the CI of five open PRs, none of which touch routing or quiz:

PR
#562fix(tutor): stop the tutor repeating itself
#536fix(learn): add a concept back after deleting it
#535feat(landing): port the v5 marketing landing
#512feat(academics): per-section Fall 2026 offerings
#507feat(documents): file-level dedup

Their pull_request runs check out a merge of head + base, so landing this on main turns all five green without touching their branches.

Relationship to #563

The three files here are lifted verbatim from #563, which diagnosed the bug and already carries the fix. backend/main.py is byte-identical to that branch's version, so #563 still auto-merges cleanly after this lands — both sides hold the same content. #563 keeps the credit for the diagnosis; this just unblocks the queue ahead of it.

Verification

  • ruff check . clean
  • Full hermetic suite: 1970 passed, 56 skipped
  • test_otel_fastapi_compat.py + test_quiz_preflight_a.py: 27 passed

`Backend (pytest)` has been red on main since the FastAPI 0.138 lock, on
test_quiz_preflight_a.py::TestQuizErrorEnvelope::test_method_not_allowed_gets_generic_code:
AttributeError: '_IncludedRouter' object has no attribute 'path'
Not test-only. otel's _get_route_details guards its FULL-match `.path` read
with `except AttributeError` but its PARTIAL-match branch does not — and a
PARTIAL match is exactly a wrong-method request. So the error escapes the
middleware and every 405 returns 500. Staging and prod install the same lock,
so that is live behaviour.
Nothing to upgrade to: the unguarded line is in every released
opentelemetry-instrumentation-fastapi through 0.65b0. services/otel_fastapi_compat.py
wraps the resolver, absorbing only AttributeError and falling back to
scope["path"] — otel's own FULL-branch fallback.
Lifted verbatim from #563 so that PR still auto-merges after this lands; it
blocks five other open PRs whose CI runs against a merge with main.
@coderabbitai

Copy link
Copy Markdown

Warning

Review limit reached

@Jose-Gael-Cruz-Lopez, you've reached your PR review limit, so we couldn't start this review.

Next review available in:52 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 02aec938-72dc-4825-9aff-5b58245d5dbd

📥 Commits

Reviewing files that changed from the base of the PR and between 4f5a7f9 and 9bba412.

📒 Files selected for processing (3)
  • backend/main.py
  • backend/services/otel_fastapi_compat.py
  • backend/tests/test_otel_fastapi_compat.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@supabase

supabaseBot commented Aug 19, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project ybgqdonkoqftwrmweuyv because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopez merged commit 38905c6 into mainAug 19, 2026
7 checks passed
@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopez deleted the fix/otel-fastapi-405-500 branch August 19, 2026 20:41
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Jose-Gael-Cruz-Lopez
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(api): stop otel turning every 405 into a 500 (unblocks 5 PRs) - #564

Merged
Jose-Gael-Cruz-Lopez merged 1 commit into
mainfrom
fix/otel-fastapi-405-500
Aug 19, 2026
Merged

fix(api): stop otel turning every 405 into a 500 (unblocks 5 PRs)#564
Jose-Gael-Cruz-Lopez merged 1 commit into
mainfrom
fix/otel-fastapi-405-500

Conversation

@Jose-Gael-Cruz-Lopez

Copy link
Copy Markdown
Member

Why this is separate

Backend (pytest) has been red on main since the FastAPI 0.138 lock, on one test:

FAILED tests/test_quiz_preflight_a.py::TestQuizErrorEnvelope::test_method_not_allowed_gets_generic_code
AttributeError: '_IncludedRouter' object has no attribute 'path'
opentelemetry/instrumentation/fastapi/__init__.py:495

This is not test-only. otel's _get_route_details guards its FULL-match .path read with except AttributeError, but its PARTIAL-match branch does not — and a PARTIAL match is exactly a wrong-method request. The error escapes the middleware, so every 405 returns 500. Staging and production install the same lock, so that is live behaviour today.

There is nothing to upgrade to: the unguarded line is present in every released opentelemetry-instrumentation-fastapi through 0.65b0. services/otel_fastapi_compat.py wraps the resolver, absorbing only AttributeError and falling back to scope["path"] — which is otel's own FULL-branch fallback.

Why now

This one failure is blocking the CI of five open PRs, none of which touch routing or quiz:

PR
#562fix(tutor): stop the tutor repeating itself
#536fix(learn): add a concept back after deleting it
#535feat(landing): port the v5 marketing landing
#512feat(academics): per-section Fall 2026 offerings
#507feat(documents): file-level dedup

Their pull_request runs check out a merge of head + base, so landing this on main turns all five green without touching their branches.

Relationship to #563

The three files here are lifted verbatim from #563, which diagnosed the bug and already carries the fix. backend/main.py is byte-identical to that branch's version, so #563 still auto-merges cleanly after this lands — both sides hold the same content. #563 keeps the credit for the diagnosis; this just unblocks the queue ahead of it.

Verification

  • ruff check . clean
  • Full hermetic suite: 1970 passed, 56 skipped
  • test_otel_fastapi_compat.py + test_quiz_preflight_a.py: 27 passed

`Backend (pytest)` has been red on main since the FastAPI 0.138 lock, on
test_quiz_preflight_a.py::TestQuizErrorEnvelope::test_method_not_allowed_gets_generic_code:
AttributeError: '_IncludedRouter' object has no attribute 'path'
Not test-only. otel's _get_route_details guards its FULL-match `.path` read
with `except AttributeError` but its PARTIAL-match branch does not — and a
PARTIAL match is exactly a wrong-method request. So the error escapes the
middleware and every 405 returns 500. Staging and prod install the same lock,
so that is live behaviour.
Nothing to upgrade to: the unguarded line is in every released
opentelemetry-instrumentation-fastapi through 0.65b0. services/otel_fastapi_compat.py
wraps the resolver, absorbing only AttributeError and falling back to
scope["path"] — otel's own FULL-branch fallback.
Lifted verbatim from #563 so that PR still auto-merges after this lands; it
blocks five other open PRs whose CI runs against a merge with main.
@coderabbitai

Copy link
Copy Markdown

Warning

Review limit reached

@Jose-Gael-Cruz-Lopez, you've reached your PR review limit, so we couldn't start this review.

Next review available in:52 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 02aec938-72dc-4825-9aff-5b58245d5dbd

📥 Commits

Reviewing files that changed from the base of the PR and between 4f5a7f9 and 9bba412.

📒 Files selected for processing (3)
  • backend/main.py
  • backend/services/otel_fastapi_compat.py
  • backend/tests/test_otel_fastapi_compat.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@supabase

supabaseBot commented Aug 19, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project ybgqdonkoqftwrmweuyv because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopez merged commit 38905c6 into mainAug 19, 2026
7 checks passed
@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopez deleted the fix/otel-fastapi-405-500 branch August 19, 2026 20:41
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Jose-Gael-Cruz-Lopez
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(api): stop otel turning every 405 into a 500 (unblocks 5 PRs) - #564

Merged
Jose-Gael-Cruz-Lopez merged 1 commit into
mainfrom
fix/otel-fastapi-405-500
Aug 19, 2026
Merged

fix(api): stop otel turning every 405 into a 500 (unblocks 5 PRs)#564
Jose-Gael-Cruz-Lopez merged 1 commit into
mainfrom
fix/otel-fastapi-405-500

Conversation

@Jose-Gael-Cruz-Lopez

Copy link
Copy Markdown
Member

Why this is separate

Backend (pytest) has been red on main since the FastAPI 0.138 lock, on one test:

FAILED tests/test_quiz_preflight_a.py::TestQuizErrorEnvelope::test_method_not_allowed_gets_generic_code
AttributeError: '_IncludedRouter' object has no attribute 'path'
opentelemetry/instrumentation/fastapi/__init__.py:495

This is not test-only. otel's _get_route_details guards its FULL-match .path read with except AttributeError, but its PARTIAL-match branch does not — and a PARTIAL match is exactly a wrong-method request. The error escapes the middleware, so every 405 returns 500. Staging and production install the same lock, so that is live behaviour today.

There is nothing to upgrade to: the unguarded line is present in every released opentelemetry-instrumentation-fastapi through 0.65b0. services/otel_fastapi_compat.py wraps the resolver, absorbing only AttributeError and falling back to scope["path"] — which is otel's own FULL-branch fallback.

Why now

This one failure is blocking the CI of five open PRs, none of which touch routing or quiz:

PR
#562fix(tutor): stop the tutor repeating itself
#536fix(learn): add a concept back after deleting it
#535feat(landing): port the v5 marketing landing
#512feat(academics): per-section Fall 2026 offerings
#507feat(documents): file-level dedup

Their pull_request runs check out a merge of head + base, so landing this on main turns all five green without touching their branches.

Relationship to #563

The three files here are lifted verbatim from #563, which diagnosed the bug and already carries the fix. backend/main.py is byte-identical to that branch's version, so #563 still auto-merges cleanly after this lands — both sides hold the same content. #563 keeps the credit for the diagnosis; this just unblocks the queue ahead of it.

Verification

  • ruff check . clean
  • Full hermetic suite: 1970 passed, 56 skipped
  • test_otel_fastapi_compat.py + test_quiz_preflight_a.py: 27 passed

`Backend (pytest)` has been red on main since the FastAPI 0.138 lock, on
test_quiz_preflight_a.py::TestQuizErrorEnvelope::test_method_not_allowed_gets_generic_code:
AttributeError: '_IncludedRouter' object has no attribute 'path'
Not test-only. otel's _get_route_details guards its FULL-match `.path` read
with `except AttributeError` but its PARTIAL-match branch does not — and a
PARTIAL match is exactly a wrong-method request. So the error escapes the
middleware and every 405 returns 500. Staging and prod install the same lock,
so that is live behaviour.
Nothing to upgrade to: the unguarded line is in every released
opentelemetry-instrumentation-fastapi through 0.65b0. services/otel_fastapi_compat.py
wraps the resolver, absorbing only AttributeError and falling back to
scope["path"] — otel's own FULL-branch fallback.
Lifted verbatim from #563 so that PR still auto-merges after this lands; it
blocks five other open PRs whose CI runs against a merge with main.
@coderabbitai

Copy link
Copy Markdown

Warning

Review limit reached

@Jose-Gael-Cruz-Lopez, you've reached your PR review limit, so we couldn't start this review.

Next review available in:52 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 02aec938-72dc-4825-9aff-5b58245d5dbd

📥 Commits

Reviewing files that changed from the base of the PR and between 4f5a7f9 and 9bba412.

📒 Files selected for processing (3)
  • backend/main.py
  • backend/services/otel_fastapi_compat.py
  • backend/tests/test_otel_fastapi_compat.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@supabase

supabaseBot commented Aug 19, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project ybgqdonkoqftwrmweuyv because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopez merged commit 38905c6 into mainAug 19, 2026
7 checks passed
@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopez deleted the fix/otel-fastapi-405-500 branch August 19, 2026 20:41
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Jose-Gael-Cruz-Lopez
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(api): stop otel turning every 405 into a 500 (unblocks 5 PRs) - #564

Merged
Jose-Gael-Cruz-Lopez merged 1 commit into
mainfrom
fix/otel-fastapi-405-500
Aug 19, 2026
Merged

fix(api): stop otel turning every 405 into a 500 (unblocks 5 PRs)#564
Jose-Gael-Cruz-Lopez merged 1 commit into
mainfrom
fix/otel-fastapi-405-500

Conversation

@Jose-Gael-Cruz-Lopez

Copy link
Copy Markdown
Member

Why this is separate

Backend (pytest) has been red on main since the FastAPI 0.138 lock, on one test:

FAILED tests/test_quiz_preflight_a.py::TestQuizErrorEnvelope::test_method_not_allowed_gets_generic_code
AttributeError: '_IncludedRouter' object has no attribute 'path'
opentelemetry/instrumentation/fastapi/__init__.py:495

This is not test-only. otel's _get_route_details guards its FULL-match .path read with except AttributeError, but its PARTIAL-match branch does not — and a PARTIAL match is exactly a wrong-method request. The error escapes the middleware, so every 405 returns 500. Staging and production install the same lock, so that is live behaviour today.

There is nothing to upgrade to: the unguarded line is present in every released opentelemetry-instrumentation-fastapi through 0.65b0. services/otel_fastapi_compat.py wraps the resolver, absorbing only AttributeError and falling back to scope["path"] — which is otel's own FULL-branch fallback.

Why now

This one failure is blocking the CI of five open PRs, none of which touch routing or quiz:

PR
#562fix(tutor): stop the tutor repeating itself
#536fix(learn): add a concept back after deleting it
#535feat(landing): port the v5 marketing landing
#512feat(academics): per-section Fall 2026 offerings
#507feat(documents): file-level dedup

Their pull_request runs check out a merge of head + base, so landing this on main turns all five green without touching their branches.

Relationship to #563

The three files here are lifted verbatim from #563, which diagnosed the bug and already carries the fix. backend/main.py is byte-identical to that branch's version, so #563 still auto-merges cleanly after this lands — both sides hold the same content. #563 keeps the credit for the diagnosis; this just unblocks the queue ahead of it.

Verification

  • ruff check . clean
  • Full hermetic suite: 1970 passed, 56 skipped
  • test_otel_fastapi_compat.py + test_quiz_preflight_a.py: 27 passed

`Backend (pytest)` has been red on main since the FastAPI 0.138 lock, on
test_quiz_preflight_a.py::TestQuizErrorEnvelope::test_method_not_allowed_gets_generic_code:
AttributeError: '_IncludedRouter' object has no attribute 'path'
Not test-only. otel's _get_route_details guards its FULL-match `.path` read
with `except AttributeError` but its PARTIAL-match branch does not — and a
PARTIAL match is exactly a wrong-method request. So the error escapes the
middleware and every 405 returns 500. Staging and prod install the same lock,
so that is live behaviour.
Nothing to upgrade to: the unguarded line is in every released
opentelemetry-instrumentation-fastapi through 0.65b0. services/otel_fastapi_compat.py
wraps the resolver, absorbing only AttributeError and falling back to
scope["path"] — otel's own FULL-branch fallback.
Lifted verbatim from #563 so that PR still auto-merges after this lands; it
blocks five other open PRs whose CI runs against a merge with main.
@coderabbitai

Copy link
Copy Markdown

Warning

Review limit reached

@Jose-Gael-Cruz-Lopez, you've reached your PR review limit, so we couldn't start this review.

Next review available in:52 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 02aec938-72dc-4825-9aff-5b58245d5dbd

📥 Commits

Reviewing files that changed from the base of the PR and between 4f5a7f9 and 9bba412.

📒 Files selected for processing (3)
  • backend/main.py
  • backend/services/otel_fastapi_compat.py
  • backend/tests/test_otel_fastapi_compat.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@supabase

supabaseBot commented Aug 19, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project ybgqdonkoqftwrmweuyv because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopez merged commit 38905c6 into mainAug 19, 2026
7 checks passed
@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopez deleted the fix/otel-fastapi-405-500 branch August 19, 2026 20:41
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Jose-Gael-Cruz-Lopez
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(api): stop otel turning every 405 into a 500 (unblocks 5 PRs) - #564

Merged
Jose-Gael-Cruz-Lopez merged 1 commit into
mainfrom
fix/otel-fastapi-405-500
Aug 19, 2026
Merged

fix(api): stop otel turning every 405 into a 500 (unblocks 5 PRs)#564
Jose-Gael-Cruz-Lopez merged 1 commit into
mainfrom
fix/otel-fastapi-405-500

Conversation

@Jose-Gael-Cruz-Lopez

Copy link
Copy Markdown
Member

Why this is separate

Backend (pytest) has been red on main since the FastAPI 0.138 lock, on one test:

FAILED tests/test_quiz_preflight_a.py::TestQuizErrorEnvelope::test_method_not_allowed_gets_generic_code
AttributeError: '_IncludedRouter' object has no attribute 'path'
opentelemetry/instrumentation/fastapi/__init__.py:495

This is not test-only. otel's _get_route_details guards its FULL-match .path read with except AttributeError, but its PARTIAL-match branch does not — and a PARTIAL match is exactly a wrong-method request. The error escapes the middleware, so every 405 returns 500. Staging and production install the same lock, so that is live behaviour today.

There is nothing to upgrade to: the unguarded line is present in every released opentelemetry-instrumentation-fastapi through 0.65b0. services/otel_fastapi_compat.py wraps the resolver, absorbing only AttributeError and falling back to scope["path"] — which is otel's own FULL-branch fallback.

Why now

This one failure is blocking the CI of five open PRs, none of which touch routing or quiz:

PR
#562fix(tutor): stop the tutor repeating itself
#536fix(learn): add a concept back after deleting it
#535feat(landing): port the v5 marketing landing
#512feat(academics): per-section Fall 2026 offerings
#507feat(documents): file-level dedup

Their pull_request runs check out a merge of head + base, so landing this on main turns all five green without touching their branches.

Relationship to #563

The three files here are lifted verbatim from #563, which diagnosed the bug and already carries the fix. backend/main.py is byte-identical to that branch's version, so #563 still auto-merges cleanly after this lands — both sides hold the same content. #563 keeps the credit for the diagnosis; this just unblocks the queue ahead of it.

Verification

  • ruff check . clean
  • Full hermetic suite: 1970 passed, 56 skipped
  • test_otel_fastapi_compat.py + test_quiz_preflight_a.py: 27 passed

`Backend (pytest)` has been red on main since the FastAPI 0.138 lock, on
test_quiz_preflight_a.py::TestQuizErrorEnvelope::test_method_not_allowed_gets_generic_code:
AttributeError: '_IncludedRouter' object has no attribute 'path'
Not test-only. otel's _get_route_details guards its FULL-match `.path` read
with `except AttributeError` but its PARTIAL-match branch does not — and a
PARTIAL match is exactly a wrong-method request. So the error escapes the
middleware and every 405 returns 500. Staging and prod install the same lock,
so that is live behaviour.
Nothing to upgrade to: the unguarded line is in every released
opentelemetry-instrumentation-fastapi through 0.65b0. services/otel_fastapi_compat.py
wraps the resolver, absorbing only AttributeError and falling back to
scope["path"] — otel's own FULL-branch fallback.
Lifted verbatim from #563 so that PR still auto-merges after this lands; it
blocks five other open PRs whose CI runs against a merge with main.
@coderabbitai

Copy link
Copy Markdown

Warning

Review limit reached

@Jose-Gael-Cruz-Lopez, you've reached your PR review limit, so we couldn't start this review.

Next review available in:52 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 02aec938-72dc-4825-9aff-5b58245d5dbd

📥 Commits

Reviewing files that changed from the base of the PR and between 4f5a7f9 and 9bba412.

📒 Files selected for processing (3)
  • backend/main.py
  • backend/services/otel_fastapi_compat.py
  • backend/tests/test_otel_fastapi_compat.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@supabase

supabaseBot commented Aug 19, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project ybgqdonkoqftwrmweuyv because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopez merged commit 38905c6 into mainAug 19, 2026
7 checks passed
@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopez deleted the fix/otel-fastapi-405-500 branch August 19, 2026 20:41
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Jose-Gael-Cruz-Lopez