From 59769df4b9860f6f0504706ca3131c619ea9a672 Mon Sep 17 00:00:00 2001 From: Nadeem Patwekar Date: Wed, 12 Nov 2025 12:08:48 +0530 Subject: [PATCH 1/4] fix: NullReferenceException and JsonReaderException in Taxonomy model; improve error handling and messaging. --- CHANGELOG.md | 12 +++++ Contentstack.Core/Models/Taxonomy.cs | 79 +++++++++++++++++++++------- Directory.Build.props | 2 +- 3 files changed, 73 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db238bf..b08d5ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +### Version: 2.25.2 +#### Date: Nov-13-2025 + +##### Fix: +- Taxonomy + - Fixed NullReferenceException in `_Url` property when Stack is null + - Fixed NullReferenceException in constructor when ContentstackClient parameter is null + - Fixed InvalidCastException in `GetContentstackError` when exception is not a WebException + - Fixed NullReferenceException in `GetContentstackError` when WebException.Response is null + - Fixed JsonReaderException in `GetContentstackError` when response is not valid JSON + - All exceptions now properly throw TaxonomyException (extends ContentstackException) with descriptive error messages + ### Version: 2.25.1 #### Date: Nov-10-2025 diff --git a/Contentstack.Core/Models/Taxonomy.cs b/Contentstack.Core/Models/Taxonomy.cs index a125833..9d7322f 100644 --- a/Contentstack.Core/Models/Taxonomy.cs +++ b/Contentstack.Core/Models/Taxonomy.cs @@ -21,6 +21,14 @@ protected override string _Url { get { + if (this.Stack == null) + { + throw new TaxonomyException("Taxonomy Stack instance is null. Please ensure the Taxonomy is properly initialized with a ContentstackClient instance."); + } + if (this.Stack.Config == null) + { + throw new TaxonomyException("Taxonomy Stack Config is null. Please ensure the ContentstackClient is properly configured."); + } Config config = this.Stack.Config; return String.Format("{0}/taxonomies/entries", config.BaseUrl); } @@ -40,6 +48,10 @@ internal Taxonomy() } internal Taxonomy(ContentstackClient stack): base(stack) { + if (stack == null) + { + throw new TaxonomyException("ContentstackClient instance cannot be null when creating a Taxonomy instance."); + } this.Stack = stack; this._StackHeaders = stack._LocalHeaders; } @@ -252,30 +264,59 @@ internal static ContentstackException GetContentstackError(Exception ex) try { - System.Net.WebException webEx = (System.Net.WebException)ex; - - using (var exResp = webEx.Response) - using (var stream = exResp.GetResponseStream()) - using (var reader = new StreamReader(stream)) + System.Net.WebException webEx = ex as System.Net.WebException; + + if (webEx != null && webEx.Response != null) { - errorMessage = reader.ReadToEnd(); - JObject data = JObject.Parse(errorMessage.Replace("\r\n", "")); + using (var exResp = webEx.Response) + { + var stream = exResp.GetResponseStream(); + if (stream != null) + { + using (stream) + using (var reader = new StreamReader(stream)) + { + errorMessage = reader.ReadToEnd(); + + if (!string.IsNullOrWhiteSpace(errorMessage)) + { + try + { + JObject data = JObject.Parse(errorMessage.Replace("\r\n", "")); - JToken token = data["error_code"]; - if (token != null) - errorCode = token.Value(); + JToken token = data["error_code"]; + if (token != null) + errorCode = token.Value(); - token = data["error_message"]; - if (token != null) - errorMessage = token.Value(); + token = data["error_message"]; + if (token != null) + errorMessage = token.Value(); - token = data["errors"]; - if (token != null) - errors = token.ToObject>(); + token = data["errors"]; + if (token != null) + errors = token.ToObject>(); + } + catch (Newtonsoft.Json.JsonException) + { + // If JSON parsing fails, use the raw error message + // errorMessage is already set from ReadToEnd() + } + } - var response = exResp as HttpWebResponse; - if (response != null) - statusCode = response.StatusCode; + var response = exResp as HttpWebResponse; + if (response != null) + statusCode = response.StatusCode; + } + } + else + { + errorMessage = webEx.Message; + } + } + } + else + { + errorMessage = ex.Message; } } catch diff --git a/Directory.Build.props b/Directory.Build.props index e15a9a2..0e81c8f 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,5 +1,5 @@ - 2.25.1 + 2.25.2 From f888bd15900650e3986fe2c24514d645fad1e76b Mon Sep 17 00:00:00 2001 From: Nadeem Patwekar Date: Wed, 12 Nov 2025 12:45:22 +0530 Subject: [PATCH 2/4] chore: version bump removed and changelog modified --- CHANGELOG.md | 15 +++++++-------- Directory.Build.props | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b08d5ef..db9a175 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,20 +1,19 @@ ### Version: 2.25.2 #### Date: Nov-13-2025 -##### Fix: -- Taxonomy - - Fixed NullReferenceException in `_Url` property when Stack is null - - Fixed NullReferenceException in constructor when ContentstackClient parameter is null - - Fixed InvalidCastException in `GetContentstackError` when exception is not a WebException - - Fixed NullReferenceException in `GetContentstackError` when WebException.Response is null - - Fixed JsonReaderException in `GetContentstackError` when response is not valid JSON - - All exceptions now properly throw TaxonomyException (extends ContentstackException) with descriptive error messages + ### Version: 2.25.1 #### Date: Nov-10-2025 ##### Enh: - Improved Error messages +##### Fix: +- Taxonomy + - Fixed NullReferenceExceptions + - Fixed InvalidCastException in `GetContentstackError` when exception is not a WebException + - Fixed JsonReaderException in `GetContentstackError` when response is not valid JSON + - All exceptions now properly throw TaxonomyException (extends ContentstackException) with descriptive error messages ### Version: 2.25.0 #### Date: Jan-07-2025 diff --git a/Directory.Build.props b/Directory.Build.props index 0e81c8f..e15a9a2 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,5 +1,5 @@ - 2.25.2 + 2.25.1 From 221b01b12486ba36a30d970229b6065e2126a8c6 Mon Sep 17 00:00:00 2001 From: Nadeem Patwekar Date: Mon, 8 Dec 2025 12:07:04 +0530 Subject: [PATCH 3/4] fix: enhance error handling for WebException across multiple models and add corresponding unit tests --- .../AssetLibraryUnitTests.cs | 34 +++++++++ .../AssetUnitTests.cs | 34 +++++++++ .../ContentTypeUnitTests.cs | 30 ++++++++ .../EntryUnitTests.cs | 36 ++++++++++ .../GlobalFieldQueryUnitTests.cs | 30 ++++++++ .../GlobalFieldUnitTests.cs | 69 +++++++++++++++++++ .../QueryUnitTests.cs | 36 ++++++++++ Contentstack.Core/Models/Asset.cs | 10 +++ Contentstack.Core/Models/AssetLibrary.cs | 10 +++ Contentstack.Core/Models/ContentType.cs | 10 +++ Contentstack.Core/Models/Entry.cs | 10 +++ Contentstack.Core/Models/GlobalField.cs | 10 +++ Contentstack.Core/Models/GlobalFieldQuery.cs | 10 +++ Contentstack.Core/Models/Query.cs | 10 +++ 14 files changed, 339 insertions(+) diff --git a/Contentstack.Core.Unit.Tests/AssetLibraryUnitTests.cs b/Contentstack.Core.Unit.Tests/AssetLibraryUnitTests.cs index a85f467..1797d2b 100644 --- a/Contentstack.Core.Unit.Tests/AssetLibraryUnitTests.cs +++ b/Contentstack.Core.Unit.Tests/AssetLibraryUnitTests.cs @@ -549,6 +549,40 @@ public void GetContentstackError_WithGenericException_ReturnsContentstackExcepti Assert.Equal("Test error", result.Message); } + [Fact] + public void GetContentstackError_WithWebException_HandlesExceptionCorrectly() + { + // Arrange + var method = typeof(AssetLibrary).GetMethod("GetContentstackError", + BindingFlags.NonPublic | BindingFlags.Static); + var webEx = new System.Net.WebException("Test error"); + + // Act + var result = method?.Invoke(null, new object[] { webEx }) as ContentstackException; + + // Assert + Assert.NotNull(result); + // When WebException has no response, it should fall back to ex.Message + Assert.NotNull(result.Message); + } + + [Fact] + public void ErrorHandling_WithWebException_ExtractsErrorMessage() + { + // Arrange + var method = typeof(AssetLibrary).GetMethod("GetContentstackError", + BindingFlags.NonPublic | BindingFlags.Static); + var errorMessage = "Asset library error"; + var ex = new Exception(errorMessage); + + // Act + var result = method?.Invoke(null, new object[] { ex }) as ContentstackException; + + // Assert + Assert.NotNull(result); + Assert.Equal(errorMessage, result.Message); + } + [Fact] public void GetHeader_WithNullLocalHeader_ReturnsStackHeaders() { diff --git a/Contentstack.Core.Unit.Tests/AssetUnitTests.cs b/Contentstack.Core.Unit.Tests/AssetUnitTests.cs index 107cb10..f560c83 100644 --- a/Contentstack.Core.Unit.Tests/AssetUnitTests.cs +++ b/Contentstack.Core.Unit.Tests/AssetUnitTests.cs @@ -536,6 +536,40 @@ public void GetContentstackError_WithGenericException_ReturnsContentstackExcepti Assert.Equal("Test error", result.Message); } + [Fact] + public void GetContentstackError_WithWebException_HandlesExceptionCorrectly() + { + // Arrange + var method = typeof(Asset).GetMethod("GetContentstackError", + BindingFlags.NonPublic | BindingFlags.Static); + var webEx = new System.Net.WebException("Test error"); + + // Act + var result = method?.Invoke(null, new object[] { webEx }) as ContentstackException; + + // Assert + Assert.NotNull(result); + // When WebException has no response, it should fall back to ex.Message + Assert.NotNull(result.Message); + } + + [Fact] + public void ErrorHandling_WithWebException_ExtractsErrorMessage() + { + // Arrange + var method = typeof(Asset).GetMethod("GetContentstackError", + BindingFlags.NonPublic | BindingFlags.Static); + var errorMessage = "Asset processing failed"; + var ex = new Exception(errorMessage); + + // Act + var result = method?.Invoke(null, new object[] { ex }) as ContentstackException; + + // Assert + Assert.NotNull(result); + Assert.Equal(errorMessage, result.Message); + } + [Fact] public void GetHeader_WithNullLocalHeader_ReturnsStackHeaders() { diff --git a/Contentstack.Core.Unit.Tests/ContentTypeUnitTests.cs b/Contentstack.Core.Unit.Tests/ContentTypeUnitTests.cs index 8d24b77..0f83efb 100644 --- a/Contentstack.Core.Unit.Tests/ContentTypeUnitTests.cs +++ b/Contentstack.Core.Unit.Tests/ContentTypeUnitTests.cs @@ -311,6 +311,36 @@ public void GetContentstackError_WithGenericException_ReturnsContentstackExcepti Assert.IsType(result); } + [Fact] + public void GetContentstackError_WithGenericException_ReturnsExceptionWithCorrectMessage() + { + // Arrange + var errorMessage = "Content type error"; + var exception = new Exception(errorMessage); + + // Act + var result = ContentType.GetContentstackError(exception); + + // Assert + Assert.NotNull(result); + Assert.Equal(errorMessage, result.Message); + } + + [Fact] + public void GetContentstackError_WithWebException_HandlesExceptionCorrectly() + { + // Arrange + var webEx = new System.Net.WebException("Test error"); + + // Act + var result = ContentType.GetContentstackError(webEx); + + // Assert + Assert.NotNull(result); + // When WebException has no response, it should fall back to ex.Message + Assert.NotNull(result.Message); + } + [Fact] public void Fetch_WithIncludeBranch_VerifiesQueryParameters() { diff --git a/Contentstack.Core.Unit.Tests/EntryUnitTests.cs b/Contentstack.Core.Unit.Tests/EntryUnitTests.cs index d7d22eb..15813c2 100644 --- a/Contentstack.Core.Unit.Tests/EntryUnitTests.cs +++ b/Contentstack.Core.Unit.Tests/EntryUnitTests.cs @@ -1704,6 +1704,42 @@ public void GetContentstackError_WithGenericException_ReturnsContentstackExcepti Assert.Equal("Test error", result.Message); } + [Fact] + public void GetContentstackError_WithWebException_HandlesExceptionCorrectly() + { + // Arrange + var method = typeof(Entry).GetMethod("GetContentstackError", + BindingFlags.NonPublic | BindingFlags.Static); + var webEx = new System.Net.WebException("Test error"); + + // Act + var result = method?.Invoke(null, new object[] { webEx }) as ContentstackException; + + // Assert + Assert.NotNull(result); + // When WebException has no response, it should fall back to ex.Message + Assert.NotNull(result.Message); + } + + [Fact] + public void ErrorHandling_WithWebException_ExtractsErrorMessage() + { + // Arrange + // This test verifies that the error handling logic properly checks for WebException + // and calls GetContentstackError to extract error messages + var method = typeof(Entry).GetMethod("GetContentstackError", + BindingFlags.NonPublic | BindingFlags.Static); + var errorMessage = "Custom error message"; + var ex = new Exception(errorMessage); + + // Act + var result = method?.Invoke(null, new object[] { ex }) as ContentstackException; + + // Assert + Assert.NotNull(result); + Assert.Equal(errorMessage, result.Message); + } + [Fact] public void GetHeader_WithNullLocalHeader_ReturnsFormHeaders() { diff --git a/Contentstack.Core.Unit.Tests/GlobalFieldQueryUnitTests.cs b/Contentstack.Core.Unit.Tests/GlobalFieldQueryUnitTests.cs index 604c3df..26a9670 100644 --- a/Contentstack.Core.Unit.Tests/GlobalFieldQueryUnitTests.cs +++ b/Contentstack.Core.Unit.Tests/GlobalFieldQueryUnitTests.cs @@ -142,6 +142,36 @@ public void GetContentstackError_WithGenericException_ReturnsContentstackExcepti Assert.IsType(result); } + [Fact] + public void GetContentstackError_WithGenericException_ReturnsExceptionWithCorrectMessage() + { + // Arrange + var errorMessage = "Global field query error"; + var exception = new Exception(errorMessage); + + // Act + var result = GlobalFieldQuery.GetContentstackError(exception); + + // Assert + Assert.NotNull(result); + Assert.Equal(errorMessage, result.Message); + } + + [Fact] + public void GetContentstackError_WithWebException_HandlesExceptionCorrectly() + { + // Arrange + var webEx = new System.Net.WebException("Test error"); + + // Act + var result = GlobalFieldQuery.GetContentstackError(webEx); + + // Assert + Assert.NotNull(result); + // When WebException has no response, it should fall back to ex.Message + Assert.NotNull(result.Message); + } + [Fact] public void Find_WithMultipleParameters_VerifiesAllQueryParameters() { diff --git a/Contentstack.Core.Unit.Tests/GlobalFieldUnitTests.cs b/Contentstack.Core.Unit.Tests/GlobalFieldUnitTests.cs index 0d9396b..03d5800 100644 --- a/Contentstack.Core.Unit.Tests/GlobalFieldUnitTests.cs +++ b/Contentstack.Core.Unit.Tests/GlobalFieldUnitTests.cs @@ -138,6 +138,75 @@ public void RemoveHeader_RemovesHeader() } #endregion + + #region GetContentstackError Tests + + [Fact] + public void GetContentstackError_WithWebException_ReturnsContentstackException() + { + // Arrange + var method = typeof(GlobalField).GetMethod("GetContentstackError", + BindingFlags.NonPublic | BindingFlags.Static); + var webEx = new System.Net.WebException("Test error"); + + // Act + var result = method?.Invoke(null, new object[] { webEx }) as Contentstack.Core.Internals.ContentstackException; + + // Assert + Assert.NotNull(result); + } + + [Fact] + public void GetContentstackError_WithGenericException_ReturnsContentstackException() + { + // Arrange + var method = typeof(GlobalField).GetMethod("GetContentstackError", + BindingFlags.NonPublic | BindingFlags.Static); + var ex = new Exception("Test error"); + + // Act + var result = method?.Invoke(null, new object[] { ex }) as Contentstack.Core.Internals.ContentstackException; + + // Assert + Assert.NotNull(result); + Assert.Equal("Test error", result.Message); + } + + [Fact] + public void GetContentstackError_WithWebException_HandlesExceptionCorrectly() + { + // Arrange + var method = typeof(GlobalField).GetMethod("GetContentstackError", + BindingFlags.NonPublic | BindingFlags.Static); + var webEx = new System.Net.WebException("Test error"); + + // Act + var result = method?.Invoke(null, new object[] { webEx }) as Contentstack.Core.Internals.ContentstackException; + + // Assert + Assert.NotNull(result); + // When WebException has no response, it should fall back to ex.Message + Assert.NotNull(result.Message); + } + + [Fact] + public void ErrorHandling_WithWebException_ExtractsErrorMessage() + { + // Arrange + var method = typeof(GlobalField).GetMethod("GetContentstackError", + BindingFlags.NonPublic | BindingFlags.Static); + var errorMessage = "Global field error"; + var ex = new Exception(errorMessage); + + // Act + var result = method?.Invoke(null, new object[] { ex }) as Contentstack.Core.Internals.ContentstackException; + + // Assert + Assert.NotNull(result); + Assert.Equal(errorMessage, result.Message); + } + + #endregion } } diff --git a/Contentstack.Core.Unit.Tests/QueryUnitTests.cs b/Contentstack.Core.Unit.Tests/QueryUnitTests.cs index f89cd7d..316f19f 100644 --- a/Contentstack.Core.Unit.Tests/QueryUnitTests.cs +++ b/Contentstack.Core.Unit.Tests/QueryUnitTests.cs @@ -1447,6 +1447,42 @@ public void GetContentstackError_WithGenericException_ReturnsContentstackExcepti Assert.IsType(result); } + [Fact] + public void GetContentstackError_WithGenericException_ReturnsExceptionWithCorrectMessage() + { + // Arrange + var method = typeof(Query).GetMethod("GetContentstackError", + BindingFlags.NonPublic | BindingFlags.Static); + var errorMessage = "Test error message"; + var ex = new Exception(errorMessage); + + // Act + var result = method?.Invoke(null, new object[] { ex }) as ContentstackException; + + // Assert + Assert.NotNull(result); + Assert.Equal(errorMessage, result.Message); + } + + [Fact] + public void ErrorHandling_WithWebException_CallsGetContentstackError() + { + // Arrange + // This test verifies that when a WebException is caught, GetContentstackError is called + // We can't easily mock a WebException with a response, but we can verify the logic path + var method = typeof(Query).GetMethod("GetContentstackError", + BindingFlags.NonPublic | BindingFlags.Static); + var webEx = new System.Net.WebException("Test error"); + + // Act + var result = method?.Invoke(null, new object[] { webEx }) as ContentstackException; + + // Assert + Assert.NotNull(result); + // When WebException has no response, it should fall back to ex.Message + Assert.NotNull(result.Message); + } + [Fact] public void And_WithExistingAndKey_ReplacesAndValue() { diff --git a/Contentstack.Core/Models/Asset.cs b/Contentstack.Core/Models/Asset.cs index 79dbd3b..26a674b 100644 --- a/Contentstack.Core/Models/Asset.cs +++ b/Contentstack.Core/Models/Asset.cs @@ -424,6 +424,16 @@ public async Task Fetch() } catch (Exception ex) { + if (ex is System.Net.WebException) + { + var contentstackError = GetContentstackError(ex); + throw new AssetException(contentstackError.Message, ex) + { + ErrorCode = contentstackError.ErrorCode, + StatusCode = contentstackError.StatusCode, + Errors = contentstackError.Errors + }; + } throw AssetException.CreateForProcessingError(ex); } } diff --git a/Contentstack.Core/Models/AssetLibrary.cs b/Contentstack.Core/Models/AssetLibrary.cs index 8c189a8..24c33f2 100644 --- a/Contentstack.Core/Models/AssetLibrary.cs +++ b/Contentstack.Core/Models/AssetLibrary.cs @@ -580,6 +580,16 @@ private async Task Exec() } catch (Exception ex) { + if (ex is System.Net.WebException) + { + var contentstackError = GetContentstackError(ex); + throw new AssetException(contentstackError.Message, ex) + { + ErrorCode = contentstackError.ErrorCode, + StatusCode = contentstackError.StatusCode, + Errors = contentstackError.Errors + }; + } throw AssetException.CreateForProcessingError(ex); } } diff --git a/Contentstack.Core/Models/ContentType.cs b/Contentstack.Core/Models/ContentType.cs index ca9a9a3..a87f7c9 100644 --- a/Contentstack.Core/Models/ContentType.cs +++ b/Contentstack.Core/Models/ContentType.cs @@ -175,6 +175,16 @@ public async Task Fetch(Dictionary param = null) } catch (Exception ex) { + if (ex is System.Net.WebException) + { + var contentstackError = GetContentstackError(ex); + throw new ContentTypeException(contentstackError.Message, ex) + { + ErrorCode = contentstackError.ErrorCode, + StatusCode = contentstackError.StatusCode, + Errors = contentstackError.Errors + }; + } throw ContentTypeException.CreateForProcessingError(ex); } } diff --git a/Contentstack.Core/Models/Entry.cs b/Contentstack.Core/Models/Entry.cs index 527b919..882a54c 100644 --- a/Contentstack.Core/Models/Entry.cs +++ b/Contentstack.Core/Models/Entry.cs @@ -1445,6 +1445,16 @@ public async Task Fetch() } catch (Exception ex) { + if (ex is System.Net.WebException) + { + var contentstackError = GetContentstackError(ex); + throw new EntryException(contentstackError.Message, ex) + { + ErrorCode = contentstackError.ErrorCode, + StatusCode = contentstackError.StatusCode, + Errors = contentstackError.Errors + }; + } throw EntryException.CreateForProcessingError(ex); } } diff --git a/Contentstack.Core/Models/GlobalField.cs b/Contentstack.Core/Models/GlobalField.cs index 6280770..46c3943 100644 --- a/Contentstack.Core/Models/GlobalField.cs +++ b/Contentstack.Core/Models/GlobalField.cs @@ -188,6 +188,16 @@ public async Task Fetch(Dictionary param = null) } catch (Exception ex) { + if (ex is System.Net.WebException) + { + var contentstackError = GetContentstackError(ex); + throw new GlobalFieldException(contentstackError.Message, ex) + { + ErrorCode = contentstackError.ErrorCode, + StatusCode = contentstackError.StatusCode, + Errors = contentstackError.Errors + }; + } throw GlobalFieldException.CreateForProcessingError(ex); } } diff --git a/Contentstack.Core/Models/GlobalFieldQuery.cs b/Contentstack.Core/Models/GlobalFieldQuery.cs index b3b5b4b..d804c1a 100644 --- a/Contentstack.Core/Models/GlobalFieldQuery.cs +++ b/Contentstack.Core/Models/GlobalFieldQuery.cs @@ -156,6 +156,16 @@ public async Task Find(Dictionary param = null) } catch (Exception ex) { + if (ex is System.Net.WebException) + { + var contentstackError = GetContentstackError(ex); + throw new ContentstackException(contentstackError.Message, ex) + { + ErrorCode = contentstackError.ErrorCode, + StatusCode = contentstackError.StatusCode, + Errors = contentstackError.Errors + }; + } throw new ContentstackException(ErrorMessages.GlobalFieldQueryError, ex); } } diff --git a/Contentstack.Core/Models/Query.cs b/Contentstack.Core/Models/Query.cs index 66c006f..ea92342 100644 --- a/Contentstack.Core/Models/Query.cs +++ b/Contentstack.Core/Models/Query.cs @@ -1947,6 +1947,16 @@ private async Task Exec() } catch (Exception ex) { + if (ex is System.Net.WebException) + { + var contentstackError = GetContentstackError(ex); + throw new QueryFilterException(contentstackError.Message, ex) + { + ErrorCode = contentstackError.ErrorCode, + StatusCode = contentstackError.StatusCode, + Errors = contentstackError.Errors + }; + } throw QueryFilterException.Create(ex); } } From 4d99277e28b22ceab1d84ff29d25c6d6b40a899c Mon Sep 17 00:00:00 2001 From: Nadeem Patwekar Date: Mon, 8 Dec 2025 12:10:08 +0530 Subject: [PATCH 4/4] chore: update changelog and bump version to 2.25.2; enhance error handling for API responses --- .talismanrc | 2 ++ CHANGELOG.md | 8 +++++++- Directory.Build.props | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.talismanrc b/.talismanrc index b1596ce..6cfd212 100644 --- a/.talismanrc +++ b/.talismanrc @@ -24,3 +24,5 @@ fileignoreconfig: checksum: b63897181a8cb5993d1305248cfc3e711c4039b5677b6c1e4e2a639e4ecb391b - filename: Contentstack.Core.Tests/RegionHandlerTest.cs checksum: 69899138754908e156aa477d775d12fd6b3fefc1a6c2afec22cb409bd6e6446c +- filename: CHANGELOG.md + checksum: bc17fd4cf564e524c686a8271033f8e6e7f5f69de8137007d1c72d5f563fe92a \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index db9a175..776e063 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,13 @@ ### Version: 2.25.2 #### Date: Nov-13-2025 - +##### Fix: +- Error Handling + - Fixed error message extraction from Contentstack API responses across all model classes + - HTTP request errors now properly extract and display actual API error messages instead of generic exception messages + - Improved error handling in Query, Entry, Asset, GlobalField, ContentType, AssetLibrary, GlobalFieldQuery, and Taxonomy classes + - Users will now see meaningful error messages (e.g., "Invalid API key", "Entry not found") instead of generic "Exception of type 'ContentstackException' was thrown" messages + - ErrorCode, StatusCode, and Errors dictionary are now properly populated from API responses ### Version: 2.25.1 #### Date: Nov-10-2025 diff --git a/Directory.Build.props b/Directory.Build.props index e15a9a2..0e81c8f 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,5 +1,5 @@ - 2.25.1 + 2.25.2