Skip to content

Fix InvalidCastException in InMemoryCacheClient.GetAsync<object>() for non-IConvertible types#468

Merged
ejsmith merged 3 commits intomainfrom
copilot/fix-invalidcastexception-cache
Mar 1, 2026
Merged

Fix InvalidCastException in InMemoryCacheClient.GetAsync<object>() for non-IConvertible types#468
ejsmith merged 3 commits intomainfrom
copilot/fix-invalidcastexception-cache

Conversation

Copy link
Contributor

Copilot AI commented Mar 1, 2026

  • Fix GetValue<T>() in InMemoryCacheClient to not route typeof(object) through Convert.ChangeType
  • Add a test to verify GetAsync<object>() works for non-IConvertible types, covering both CloneValues=false and CloneValues=true
Original prompt

This section details on the original issue you should resolve

<issue_title>InMemoryCacheClient.GetAsync() throws InvalidCastException for non-IConvertible types</issue_title>
<issue_description>InMemoryCacheClient.CacheEntry.GetValue(). When T is object, it matches the TypeHelper.ObjectType check and routes through Convert.ChangeType(val, typeof(object)), which requires the stored value to implement IConvertible. It should just return the value directly since everything is already an object.

Minimal repro:

using Foundatio.Caching;var cache = new InMemoryCacheClient();// Store a complex object that doesn't implement IConvertibleawait cache.SetAsync("key", new MyData("hello", 42));// This throws: System.InvalidCastException: Object must implement IConvertible.var result = await cache.GetAsync("key");Console.WriteLine(result.Value); // never reachedpublic record MyData(string Name, int Value);
Stack trace:

System.InvalidCastException: Object must implement IConvertible.   at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)   at Foundatio.Caching.InMemoryCacheClient.CacheEntry.GetValueT   at Foundatio.Caching.InMemoryCacheClient.GetAsyncT
Root cause in CacheEntry.GetValue():

public T GetValue(){    object val = Value;    var t = typeof(T);    // BUG: typeof(object) matches here, falls into Convert.ChangeType    if (t == TypeHelper.BoolType || t == TypeHelper.StringType || ... || t == TypeHelper.ObjectType || t.IsNumeric())        return (T)Convert.ChangeType(val, t);  // throws for non-IConvertible values    ...    return (T)val;  // this path works fine but is never reached for T=object}
Fix: Add an early return before the Convert.ChangeType line:

if (t == TypeHelper.ObjectType)    return (T)val;
Or move ObjectType out of the Convert.ChangeType branch entirely. The direct cast (T)val (which is (object)val) always succeeds and is what the final fallback does anyway.</issue_description>

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


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

…ypes

Co-authored-by: ejsmith <282584+ejsmith@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix InvalidCastException in InMemoryCacheClient.GetAsync Fix InvalidCastException in InMemoryCacheClient.GetAsync&lt;object&gt;() for non-IConvertible types Mar 1, 2026
@ejsmith ejsmith marked this pull request as ready for review March 1, 2026 06:42
Co-authored-by: ejsmith <282584+ejsmith@users.noreply.github.com>
@ejsmith ejsmith merged commit 877f769 into main Mar 1, 2026
3 of 4 checks passed
@ejsmith ejsmith deleted the copilot/fix-invalidcastexception-cache branch March 1, 2026 06:59
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.

InMemoryCacheClient.GetAsync<object>() throws InvalidCastException for non-IConvertible types

3 participants