{"record":{"id":"87efbf05d3b370fb","repo":"vllm-project/vllm","slug":"invalid-keys-format","errorCode":null,"errorMessage":"Invalid keys format","messagePattern":"Invalid keys format","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"vllm/distributed/kv_transfer/kv_connector/v1/hf3fs/hf3fs_metadata_server.py","lineNumber":350,"sourceCode":"\n        try:\n            self.state.confirm_write_for_keys(rank, confirmations, pages_to_release)\n\n            return Response(status_code=204)\n\n        except Exception as e:\n            logger.error(\"Confirm write for keys failed: %s\", e)\n            raise HTTPException(\n                status_code=500, detail=f\"Confirmation failed: {str(e)}\"\n            ) from e\n\n    async def batch_key_exists(self, request: Request):\n        \"\"\"Check if multiple keys exist in metadata.\"\"\"\n        data = await self._read_json(request)\n        keys = data.get(\"keys\", [])\n\n        if not isinstance(keys, list):\n            raise HTTPException(status_code=400, detail=\"Invalid keys format\")\n\n        try:\n            exists_results = self.state.batch_key_exists(keys)\n            return self._json_response({\"exists\": exists_results})\n        except Exception as e:\n            raise HTTPException(\n                status_code=500, detail=f\"Key existence check failed: {str(e)}\"\n            ) from e\n\n    async def get_key_locations(self, request: Request):\n        \"\"\"Get page indices for keys on a specific rank.\"\"\"\n        data = await self._read_json(request)\n        rank = data.get(\"rank\")\n        keys = data.get(\"keys\", [])\n\n        # Validate input format\n        if rank is None or not isinstance(keys, list):\n            raise HTTPException(","sourceCodeStart":332,"sourceCodeEnd":368,"githubUrl":"https://github.com/vllm-project/vllm/blob/c794754062d49a8fdb63ab3c5215b488b865030c/vllm/distributed/kv_transfer/kv_connector/v1/hf3fs/hf3fs_metadata_server.py#L332-L368","documentation":"HTTP 400 from the HF3FS metadata server's batch_key_exists endpoint when the POST body's 'keys' field is present but not a JSON list (it defaults to [] when absent, so only a wrong-typed value triggers this). The server validates the shape before touching state, so nothing is mutated when this is raised. It indicates the client serialized the keys array incorrectly.","triggerScenarios":"POST to the key-existence route with {'keys': 'my_key'} or {'keys': {'k': 1}} instead of {'keys': ['my_key']}; sending a JSON string body that decodes to a non-list.","commonSituations":"Client code that json.dumps a single key instead of a list of keys; schema drift between connector and metadata server versions; ad-hoc curl tests with malformed bodies.","solutions":["Send 'keys' as a JSON array, e.g. {'keys': ['sess|block0', 'sess|block1']}.","Omitting 'keys' entirely is also accepted (defaults to an empty list) if you only want a no-op check.","Align connector client and metadata server versions if the wire format changed."],"exampleFix":"// before\n{\"keys\": \"sess|blk\"}\n// after\n{\"keys\": [\"sess|blk\"]}","handlingStrategy":"validation","validationCode":"assert isinstance(keys, list) and all(isinstance(k, str) for k in keys)\nclient.post(\"keys/batch_key_exists\", json={\"keys\": keys})","typeGuard":"def is_key_list(v) -> bool:\n    return isinstance(v, list) and all(isinstance(k, str) for k in v)","tryCatchPattern":null,"preventionTips":["Normalize keys to strings at the client boundary","Reuse the provided client class rather than raw requests"],"tags":["hf3fs","metadata-server","http-400","request-validation"],"backgroundTag":null,"analyzedSha":"c794754062d49a8fdb63ab3c5215b488b865030c","analyzedAt":"2026-08-14T21:17:39.825Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}