Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 17, 2025

Fix LangCache clear() 400 error by using flush() API

Summary

The LangCache API returns 400 Bad Request: "attributes: cannot be blank" when clear() attempts to delete all entries by passing attributes={} to delete_query(). The fix uses the LangCache SDK's dedicated flush() method to properly delete all entries.

Changes

Core Fix

  • delete() and adelete() - Now call self._client.flush() and self._client.flush_async() respectively to delete all cache entries using the proper API endpoint.

Additional Improvements

  • delete_by_attributes() and adelete_by_attributes() - Now raise ValueError if called with an empty attributes dictionary. This prevents misuse and provides a clear error message: "Cannot delete by attributes with an empty attributes dictionary." Users should use delete() or clear() to delete all entries, or provide specific attributes to filter deletions.

Tests

  • Updated tests to verify flush() is called for delete() and clear()
  • Updated tests to verify ValueError is raised when delete_by_attributes() is called with empty attributes
  • Fixed test mocks to consistently use "deleted_entries_count" key matching the SDK

How This Fixes The Issue

Original Problem:

cache.clear()
# → delete() → delete_query(attributes={})
# → API returns 400: "attributes: cannot be blank."

Fixed Implementation:

cache.clear()
# → delete() → flush()
# → API deletes all entries successfully

cache.delete_by_attributes({})
# → Raises ValueError with clear error message
# → Prevents misuse and guides users to correct methods

Testing

  • ✅ All 22 tests pass

  • ✅ Tests verify flush() is called for clearing all entries

  • ✅ Tests verify ValueError is raised for empty attributes with clear error message

  • ✅ Test mocks consistently use the correct SDK key names

  • ✅ Manual verification confirms the fix resolves the original issue

  • Fixes Error when calling LangCacheSemanticCache.clear() method #427

Original prompt

This section details on the original issue you should resolve

<issue_title>Error when calling LangCacheSemanticCache.clear() method</issue_title>
<issue_description>An API error is raised when calling the clear() method.

A cloud db and service does exist.

Minimum reproducible example:

` from redisvl.extensions.cache.llm.langcache import LangCacheSemanticCache
import os

cache = LangCacheSemanticCache(
api_key=os.environ.get('LANGCACHE_API_KEY'),
cache_id=os.environ.get('LANGCACHE_ID')
)

cache.store(prompt='hello world', response='hello from langcache')

result = cache.check('hello world!')
print(result)

cache.clear()`

13:30:09 httpx INFO HTTP Request: POST https://aws-us-east-1.langcache.redis.io/v1/caches/56f7ba9bee374701a1253f21cd1ac35e/entries "HTTP/1.1 201 Created" 13:30:09 httpx INFO HTTP Request: POST https://aws-us-east-1.langcache.redis.io/v1/caches/56f7ba9bee374701a1253f21cd1ac35e/entries/search "HTTP/1.1 200 OK" [{'entry_id': '5eb63bbbe01eeed093cb22bb8f5acdc3', 'prompt': 'hello world', 'response': 'hello from langcache', 'vector_distance': 0.05443430000000005, 'inserted_at': 0.0, 'updated_at': 0.0}] 13:30:09 httpx INFO HTTP Request: DELETE https://aws-us-east-1.langcache.redis.io/v1/caches/56f7ba9bee374701a1253f21cd1ac35e/entries "HTTP/1.1 400 Bad Request" Traceback (most recent call last): File "/Users/justin.cechmanek/Documents/redis-ai-resources/test_langcache.py", line 15, in <module> cache.clear() File "/Users/justin.cechmanek/.pyenv/versions/redis-ai-res/lib/python3.11/site-packages/redisvl/extensions/cache/llm/langcache.py", line 557, in clear self.delete() File "/Users/justin.cechmanek/.pyenv/versions/redis-ai-res/lib/python3.11/site-packages/redisvl/extensions/cache/llm/langcache.py", line 542, in delete self._client.delete_query(attributes={}) File "/Users/justin.cechmanek/.pyenv/versions/redis-ai-res/lib/python3.11/site-packages/langcache/sdk.py", line 227, in delete_query raise errors.BadRequestErrorResponseContent(response_data, http_res) langcache.errors.badrequesterrorresponsecontent.BadRequestErrorResponseContent: {"detail":"attributes: cannot be blank.","status":400,"title":"Invalid Request","type":"/errors/invalid-data"}</issue_description>

<agent_instructions>Create a new branch and work on ensuring we don't send attributes within clear() or any other method if there are no attributes to send, i.e. it's an empty dictionary.</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@abrookins We definitely need integration tests for this. 🙄 @abrookins @justin-cechmanek Did you create your LangCache instance with attributes? We probably need to avoid sending it blank regardless!

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

… empty attributes

- Changed delete() and adelete() to raise NotImplementedError
- Added validation to delete_by_attributes() and adelete_by_attributes() to reject empty attributes
- Updated all related tests to verify new behavior
- Added new tests for delete_by_attributes with both valid and empty attributes

Co-authored-by: abrookins <97182+abrookins@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix error when calling LangCacheSemanticCache.clear() method Fix LangCache clear() 400 error by rejecting unsupported delete-all operations Nov 17, 2025
Copilot AI requested a review from abrookins November 17, 2025 22:09
Copilot finished work on behalf of abrookins November 17, 2025 22:09
@abrookins
Copy link
Collaborator

@copilot The API deletes all entries unless you give it attributes to filter on.

…pty attributes

- Changed delete() to use self._client.flush() instead of raising NotImplementedError
- Changed adelete() to use self._client.flush_async()
- Updated error messages in delete_by_attributes to suggest using delete()/clear()
- Updated all tests to verify flush() is called
- This fixes the 400 error by using the proper API endpoint for clearing all entries

Co-authored-by: abrookins <97182+abrookins@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Nov 17, 2025

@copilot The API deletes all entries unless you give it attributes to filter on.

You're right! I found that the LangCache SDK provides a flush() method specifically for deleting all entries. Changed the implementation to use self._client.flush() instead of delete_query(attributes={}). This avoids sending the attributes field entirely and resolves the 400 error. Commit: 8d2549e

Copilot AI changed the title Fix LangCache clear() 400 error by rejecting unsupported delete-all operations Fix LangCache clear() 400 error by using flush() API Nov 17, 2025
Copilot finished work on behalf of abrookins November 17, 2025 23:09
@abrookins
Copy link
Collaborator

@copilot No need to raise on an empty dict; just ignore it.

- Changed delete_by_attributes() to return {} when attributes is empty
- Changed adelete_by_attributes() to return {} when attributes is empty
- Updated tests to verify empty attributes are ignored without calling API
- This prevents accidentally calling API with empty dict which would cause 400 error

Co-authored-by: abrookins <97182+abrookins@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Nov 17, 2025

@copilot No need to raise on an empty dict; just ignore it.

Changed delete_by_attributes() and adelete_by_attributes() to return {} when attributes is empty instead of raising ValueError. Now they silently ignore empty dicts without making an API call. Commit: 5d02f58

Copilot finished work on behalf of abrookins November 17, 2025 23:54
@abrookins
Copy link
Collaborator

@copilot Those client methods return object of this class:

class DeleteQueryResponse(BaseModel):
    r"""Response indicating the result of a cache entries deletion operation"""

    deleted_entries_count: Annotated[int, pydantic.Field(alias="deletedEntriesCount")]
    r"""The number of cache entries successfully deleted."""

So technically, an empty dict return value is incorrect; use a dict with the correct shape: {"deleted_entries_count": 0}.

- Changed delete_by_attributes() to return {"deleted_entries_count": 0} instead of {}
- Changed adelete_by_attributes() to return {"deleted_entries_count": 0} instead of {}
- Updated tests to verify correct response shape
- This matches the DeleteQueryResponse structure from LangCache SDK

Co-authored-by: abrookins <97182+abrookins@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Nov 18, 2025

@copilot Those client methods return object of this class:

class DeleteQueryResponse(BaseModel):

...

Fixed to return {"deleted_entries_count": 0} instead of {} when attributes is empty. This matches the DeleteQueryResponse shape from the LangCache SDK. Commit: cd08209

Copilot finished work on behalf of abrookins November 18, 2025 01:05
@abrookins abrookins marked this pull request as ready for review November 18, 2025 01:19
Copilot AI review requested due to automatic review settings November 18, 2025 01:19
Copilot finished reviewing on behalf of abrookins November 18, 2025 01:21
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR fixes a critical bug where calling LangCache.clear() resulted in a 400 Bad Request error. The fix replaces the problematic delete_query(attributes={}) call with the proper flush() API method, and adds defensive handling for empty attributes.

  • Replaces delete_query(attributes={}) with flush()/flush_async() in delete() and adelete() methods
  • Adds early return for empty attributes in delete_by_attributes() and adelete_by_attributes() to prevent API errors
  • Adds comprehensive test coverage for clear, delete, and delete_by_attributes operations

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
redisvl/extensions/cache/llm/langcache.py Updates delete() and adelete() to use flush() API; adds empty attributes guard in delete_by_attributes() and adelete_by_attributes()
tests/unit/test_langcache_semantic_cache.py Updates existing tests to verify flush() is called; adds new tests for clear(), aclear(), and empty attributes handling

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@abrookins
Copy link
Collaborator

@copilot The SDK returns deleted_entries_count. All tests, mocks, etc. should be using this key.

- Updated test mocks to use "deleted_entries_count" instead of "deleted_count"
- This matches the actual DeleteQueryResponse from LangCache SDK
- All tests now consistently use the correct key name

Co-authored-by: abrookins <97182+abrookins@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Nov 18, 2025

@copilot The SDK returns deleted_entries_count. All tests, mocks, etc. should be using this key.

Updated all test mocks to use deleted_entries_count consistently. The implementation already used the correct key; only the test mocks needed to be fixed. Commit: cf800f9

Copilot finished work on behalf of abrookins November 18, 2025 17:36
Copy link
Collaborator

@abrookins abrookins left a comment

Choose a reason for hiding this comment

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

LGTM

Comment on lines 607 to 609
if not attributes:
# No attributes provided, return result with zero deletions
return {"deleted_entries_count": 0}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should we add a warning here? Would it be helpful to the end user?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Actually, thanks for asking about this. I've reconsidered and think raising an exception is best instead!

Copy link
Collaborator

@bsbodden bsbodden left a comment

Choose a reason for hiding this comment

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

Look good, I will implement in the Java version and confirm end-to-end functionality

@abrookins
Copy link
Collaborator

@copilot In adelete_by_attributes and delete_by_attributes, raise an exception if attributes is an empty dict, something like ValueError("Cannot delete by attributes with an empty attributes dictionary.") Update tests, docstrings, etc.

@abrookins
Copy link
Collaborator

@copilot Try again: In adelete_by_attributes and delete_by_attributes, raise an exception if attributes is an empty dict, something like ValueError("Cannot delete by attributes with an empty attributes dictionary.") Update tests, docstrings, etc.

- Changed delete_by_attributes() to raise ValueError instead of returning {"deleted_entries_count": 0}
- Changed adelete_by_attributes() to raise ValueError instead of returning {"deleted_entries_count": 0}
- Updated docstrings to indicate attributes cannot be empty and document the ValueError
- Updated tests to verify ValueError is raised with empty attributes
- Error message: "Cannot delete by attributes with an empty attributes dictionary."

Co-authored-by: abrookins <97182+abrookins@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Nov 18, 2025

@copilot Try again: In adelete_by_attributes and delete_by_attributes, raise an exception if attributes is an empty dict, something like ValueError("Cannot delete by attributes with an empty attribute...

Updated delete_by_attributes() and adelete_by_attributes() to raise ValueError("Cannot delete by attributes with an empty attributes dictionary.") when attributes is empty. Updated docstrings to document this and updated tests to verify the exception is raised. Commit: 414ad66

Copilot finished work on behalf of abrookins November 18, 2025 22:24
@abrookins abrookins merged commit 62dc045 into main Nov 18, 2025
68 checks passed
@abrookins abrookins deleted the copilot/fix-langcache-clear-method branch November 18, 2025 22:48
Sign up for free to 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.

Error when calling LangCacheSemanticCache.clear() method

4 participants