Nobody has started this yet — be first.
Business impact
A user who wants to remove every tag from a note (e.g. PATCH {"tags": []}) gets a 200 OK response... and their tags are silently left unchanged. There's no error, no indication anything went wrong -- the API just lies about having applied the update. That's worse than a visible failure: the user believes the note is untagged, a client app's local cache shows it untagged, but the server disagrees. This class of bug (silent no-op on a valid, explicit request) is exactly the kind that produces confusing bug reports days later ("I cleared this ages ago, why is it still tagged?") instead of an immediate, traceable failure.
Problem
PATCH /notes/{id} is documented as: "Only fields present in the payload are changed." Sending {"tags": []} means "I am explicitly setting tags to be empty," and it should be honored exactly like sending any other explicit value for tags. Instead, the empty list is silently treated as if the field weren't sent at all.
Current behavior
PATCH /notes/{id} with body {"tags": []} returns 200 OK, but the note's tags remain unchanged -- the API reports success while silently discarding the requested change.
Expected behavior
PATCH /notes/{id} with body {"tags": []} clears the note's tags -- the response's tags field is [], and this persists (a subsequent GET shows [] too).
Steps to reproduce
cd fastapi/notes_api
source .venv/bin/activate
uvicorn app.main:app --reload &
ID=$(curl -s -X POST http://127.0.0.1:8000/notes -H "Content-Type: application/json"
-d '{"title":"Groceries","content":"milk","tags":["work","urgent"]}' | python3 -c 'import json,sys;print(json.load(sys.stdin)["id"])')
curl -s -X PATCH "http://127.0.0.1:8000/notes/$ID" -H "Content-Type: application/json"
-d '{"tags":[]}'
Why this matters
update_note builds data = payload.model_dump(exclude_unset=True), which correctly distinguishes "field not sent" from "field sent as an empty/falsy value" -- exclude_unset=True is precisely the tool for that distinction, and it's already being used correctly. The bug is in how the tags branch then reads data: it checks truthiness of the value instead of checking whether the key is present, throwing away the information model_dump just gave it.
Suggested approach
Compare how the tags branch in update_note checks data against how the title and content branches immediately above it check the same data dict. title/content can't actually be empty strings (both have min_length=1), which is exactly why this class of bug doesn't show up for them -- but tags genuinely can be an empty, still-meaningfully-sent list.
Acceptance criteria
Verification
.venv/bin/pytest practicetickets/test_ticket04_patch_clear_tags_ignored.py -v
Hints (0/2)
Try it without hints first — the reading is the exercise.
Working on this ticket
Work on a branch named for the ticket — that's what you'll submit.
Branch off your fork
$git checkout -b fix/patch-clear-tags-ignoredFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin fix/patch-clear-tags-ignoredSubmit it below
Paste your fork URL and the branch name, with a short write-up of the root cause.
Questions
Ask about anything unclear in the ticket — the maintainer and anyone who has solved it can answer. Please don't post full solutions.
Sign in to ask a question or reply.
Sign in./data/notes.dbOr run it via Docker instead:
cd fastapi/notes_api
docker compose up --build # API on http://127.0.0.1:8000, /docs included
SQLite data is written inside the container to /app/data/notes.db, backed by the notes-data named volume declared in docker-compose.yml -- it survives docker compose restart and re-running docker compose up after down (without -v).
Work the tickets in practicetickets/ (ticket01 through ticket07); each names one pytest file in the same directory, separate from the project's own tests/ suite:
.venv/bin/pytest practicetickets/test_ticket01_tag_length_boundary.py -v # a single ticket
./practicetickets/run_tickets.sh # all 7, pass/fail summary
./practicetickets/run_tickets.sh -v # summary + full output
Note: ticket 02's bug also breaks two pre-existing tests in tests/test_notes.py (test_search_by_q_matches_title_and_content_case_insensitively and test_filter_by_tag_and_q_are_combinable) -- that's expected, and fixing ticket 02 should bring tests/ back to fully green. Run the main suite with .venv/bin/pytest tests/ -v.
Level 1
Fix a bug
Read existing behaviour, correct it.