Skip to content

fix(reader): answer OPTIONS on the topics API instead of returning 500 - #4024

Open
polylane[bot] wants to merge 1 commit into
masterfrom
polylane/autofix/xdkn1dtpbel2
Open

polylane[bot] wants to merge 1 commit into
masterfrom
polylane/autofix/xdkn1dtpbel2

Conversation

@polylane

@polylane polylane Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

The public topics API answered browser CORS preflight requests with a 500, so cross-origin clients that read topics could not load their data. The view only handled GET and POST and returned nothing for OPTIONS. After this change it answers OPTIONS with 204 and any other unsupported method with 405. The view returned None for any method it did not branch on, which Django turns into a 500. A live OPTIONS check showed both topics routes failing while the sibling find-refs view answered 204. The change adds the missing preflight and fallback responses.

Production impact at ec9e648: Topics API keeps working; OPTIONS gains a 204 answer

Fix walkthrough

Watch the fix walkthrough

Watch the fix explained (1:22). Recorded for commit ec9e648889a49acd26e38ea92dbf7e3e6eefc9ce.

Full analysis
flowchart TD
  A["Browser on kvod-harav.com"] -->|"OPTIONS /api/topics/meat (CORS preflight)"| B["nginx: adds Access-Control-Allow-Origin"]
  B --> C["Django router to topics_api"]
  C --> D{"request.method"}
  D -->|"GET / POST"| E["jsonResponse (unchanged)"]
  D -->|"OPTIONS"| F["new branch: HttpResponse 204"]
  D -->|"other"| G["new branch: HttpResponseNotAllowed 405"]
  F --> H["preflight succeeds, follow-up GET allowed"]
Loading
Detection evidence

Affected: Gcp account production-deployment

Production impact

The diff touches only reader/views.py#topics_api and a new test. It adds an OPTIONS branch and an HttpResponseNotAllowed fallback; the GET and POST bodies are untouched, so the response those requests return does not change. The deployed web pods (production-web-*, service web-production) expose no provider metrics, so my observability read is empty, but the change is additive and removes a None return rather than introducing a new path.

Affected resources (8)
  • //container.googleapis.com/projects/production-deployment/locations/us-east1-b/clusters/cluster-1/k8s/default/Service/web-production
  • //container.googleapis.com/projects/production-deployment/locations/us-east1-b/clusters/cluster-1/k8s/default/Pod/production-web-597ff6f7cb-7xb28
  • //container.googleapis.com/projects/production-deployment/locations/us-east1-b/clusters/cluster-1/k8s/default/Pod/production-web-597ff6f7cb-bxgrl
  • //container.googleapis.com/projects/production-deployment/locations/us-east1-b/clusters/cluster-1/k8s/default/Pod/production-web-597ff6f7cb-cwx8d
  • //container.googleapis.com/projects/production-deployment/locations/us-east1-b/clusters/cluster-1/k8s/default/Pod/production-web-597ff6f7cb-fbp9d
  • //container.googleapis.com/projects/production-deployment/locations/us-east1-b/clusters/cluster-1/k8s/default/Pod/production-web-597ff6f7cb-fmr47
  • //container.googleapis.com/projects/production-deployment/locations/us-east1-b/clusters/cluster-1/k8s/default/Pod/production-web-597ff6f7cb-pnbv7
  • //container.googleapis.com/projects/production-deployment/locations/us-east1-b/clusters/cluster-1/k8s/default/Pod/production-web-597ff6f7cb-t9qlz

Observability

  • The existing 500 signal is the GCP Cloud Logging event jsonOptions /api/topics/ with jsonPayload.status=500; after the fix this stops firing for OPTIONS.
  • The new OPTIONS path returns 204 and no body, visible in the web access log as a normal status for the same route.
  • No new telemetry is added; the corrected behavior is directly observable in the existing access-log status field.

Polylane assessed this pull request at ec9e648.

Causal chain
  • Signal (log template): OPTIONS /api/topics/ returns HTTP 500 (jsonPayload.status=500)
  • Surfacing site: GKE default-namespace pods production-web-* (container web), cluster-1, gcp account production-deployment at Sefaria/Sefaria-Project:reader/views.py#topics_api
  • Mechanism: topics_api handles only GET and POST. For an OPTIONS request no branch matches, the function returns None, and Django raises ValueError (view did not return an HttpResponse), answering 500.
  • Producer: topics_api view in Sefaria/Sefaria-Project, at reader/views.py#topics_api
  • Trigger: A CORS preflight (OPTIONS) from the consumer site kvod-harav.com to the public topics API
  • Last observed: 2026-11-12T22:41:58Z
  • Blast radius: 0 other resource(s), unknown other tenant(s); data at risk: none named
  • Producer evidence:
    • curl -X OPTIONS https://www.sefaria.org/api/topics/meat returned 500 at 2026-11-12T22:41:58Z on both /api/topics/ and /api/v2/topics/
    • curl -X OPTIONS https://www.sefaria.org/api/find-refs returned 204 with CORS headers, and GET /api/topics/meat returned 200, so the 500 is method-specific to topics_api
    • reader/views.py#topics_api body branches only on request.method == "GET" and "POST" and has no fallback; sefaria/system/decorators.py#catch_error_as_json returns the function's None unchanged
    • sefaria/urls_shared.py maps api/topics/path:topic and api/v2/topics/path:topic to reader_views.topics_api
    • reproducer test reader/tests/topics_api_methods_test.py fails on the unfixed view and passes with the OPTIONS branch (204) and the 405 fallback
2 files changed (+38/-0)
  • reader/tests/topics_api_methods_test.py: added, +32/-0
  • reader/views.py: modified, +6/-0

View autofix


Generated by Polylane. You can ask follow-ups by mentioning @polylane in a comment. If you close this pull request without merging, add a comment that says why. Polylane reads it to make its next fixes better.

Co-authored-by: polylane[bot] <277585245+polylane[bot]@users.noreply.github.com>
@polylane polylane Bot added polylane severity:medium Polylane autofix severity: medium labels Nov 12, 2026
@polylane
polylane Bot requested review from saengel and yitzhakc November 12, 2026 22:47

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

polylane severity:medium Polylane autofix severity: medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant