Skip to content

[Bugfix] Reject empty keys in HTTP metadata server#2770

Merged
stmatengss merged 3 commits into
kvcache-ai:mainfrom
VectorPeak:codex/http-metadata-empty-key
Jul 8, 2026
Merged

[Bugfix] Reject empty keys in HTTP metadata server#2770
stmatengss merged 3 commits into
kvcache-ai:mainfrom
VectorPeak:codex/http-metadata-empty-key

Conversation

@VectorPeak

@VectorPeak VectorPeak commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Description

What Problem This Solves

The Python HTTP metadata server currently treats a missing key query parameter as an empty string. As a result, requests such as PUT /metadata or PUT /metadata?key= can operate on self.store[""] instead of being rejected.

This can create accidental empty-string metadata entries when callers omit the query parameter, and later empty-key requests can then appear valid instead of surfacing the original bad request.

Changes

  • Adds metadata key validation in KVBootstrapServer._handle_metadata() before dispatching GET, PUT, or DELETE handling.
  • Rejects missing, empty, and whitespace-only metadata keys with HTTP 400.
  • Strips valid non-empty metadata keys before they are passed to the existing handler path.

Evidence

  • Adds focused handler-level unit coverage for missing keys across GET, PUT, and DELETE.
  • Adds coverage for empty and whitespace-only keys.
  • Adds coverage for stripping leading and trailing whitespace before metadata operations, plus a valid-key PUT/GET round-trip test to confirm normal metadata storage and retrieval still works.

Possible call chain / impact

External metadata requests enter through /metadata, then KVBootstrapServer._handle_metadata() dispatches to _handle_get(), _handle_put(), or _handle_delete().

This change affects only the Python HTTP metadata server key handling path: missing, empty, and whitespace-only key query parameters are rejected, while valid non-empty keys are stripped before continuing through the existing handler path.

Module

  • Transfer Engine (mooncake-transfer-engine)
  • Mooncake Store (mooncake-store)
  • Mooncake EP (mooncake-ep)
  • Mooncake PG (mooncake-pg)
  • Integration (mooncake-integration)
  • P2P Store (mooncake-p2p-store)
  • Python Wheel (mooncake-wheel)
  • Common (mooncake-common)
  • Mooncake RL (mooncake-rl)
  • CI/CD
  • Docs
  • Other

Type of Change

  • Bug fix
  • New feature
  • Refactor
  • Breaking change
  • Documentation update
  • Performance improvement
  • Other

How Has This Been Tested?

Focused unit coverage validates the metadata handler directly:

  • missing key is rejected for GET, PUT, and DELETE
  • empty key is rejected
  • whitespace-only key is rejected
  • valid keys with leading/trailing whitespace are stripped before PUT/GET operations
  • valid non-empty keys still round-trip through PUT and GET

Test commands:

python -m pytest mooncake-wheel/tests/test_http_metadata_server.py -q
python -m py_compile mooncake-wheel/mooncake/http_metadata_server.py mooncake-wheel/tests/test_http_metadata_server.py
git diff --check

Test results:

  • Unit tests pass
  • Integration tests pass (if applicable)
  • Manual testing done (describe below)

Checklist

  • I have performed a self-review of my own code
  • I have formatted my code using ./scripts/code_format.sh
  • I have run pre-commit run --all-files and all hooks pass
  • I have updated the documentation (if applicable)
  • I have added tests to prove my changes are effective
  • For changes >500 LOC: I have filed an RFC issue

AI Assistance Disclosure

  • No AI tools were used
  • AI tools were used (specify below)

AI assistance was used to identify the empty-key API contract issue, inspect the affected handler path, and draft focused validation coverage. The human submitter is responsible for reviewing and validating the final changes.

Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces validation to reject empty or whitespace-only metadata keys with a 400 Bad Request response in http_metadata_server.py, and adds corresponding unit tests in test_http_metadata_server.py. The reviewer identified two issues: first, the metadata key is not stripped for subsequent operations, meaning keys with leading or trailing whitespace are still processed; second, the error response returns plain text but incorrectly specifies content_type='application/json'. A code suggestion was provided to strip the key and update the content type to text/plain.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +65 to +67
if not key.strip():
return web.Response(text='metadata key is required', status=400,
content_type='application/json')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Issue 1: Key is not stripped for subsequent operations

While not key.strip() correctly rejects empty or whitespace-only keys, the original unstripped key (which may contain leading or trailing whitespaces, e.g., " valid ") is still passed to the subsequent handlers (_handle_get, _handle_put, _handle_delete). It is safer and more robust to strip the key before performing any operations on it.

Issue 2: Invalid JSON Content-Type

The response returns plain text ('metadata key is required') but specifies content_type='application/json'. This is technically incorrect and can cause JSON parsing errors on clients that strictly parse the response body based on the Content-Type header. It should be changed to 'text/plain'.

Suggested change
if not key.strip():
return web.Response(text='metadata key is required', status=400,
content_type='application/json')
key = key.strip()
if not key:
return web.Response(text='metadata key is required', status=400,
content_type='text/plain')

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review. I addressed both points:

  • key is now stripped before dispatching to GET/PUT/DELETE handlers, so values like " valid " are stored and looked up as "valid".
  • The 400 response now uses content_type='text/plain' to match the plain-text error body.

I also added focused tests covering the text/plain error response and the whitespace-stripping behavior before metadata operations.

Validation run locally:

python -m pytest mooncake-wheel/tests/test_http_metadata_server.py -q
python -m py_compile mooncake-wheel/mooncake/http_metadata_server.py mooncake-wheel/tests/test_http_metadata_server.py
git diff --check

@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
Comment thread mooncake-wheel/mooncake/http_metadata_server.py Outdated
Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
@stmatengss
stmatengss merged commit f1c762a into kvcache-ai:main Jul 8, 2026
27 checks passed
fy2462 pushed a commit to fy2462/Mooncake that referenced this pull request Jul 20, 2026
---------

Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants