Skip to content

Conversation

@hiragram
Copy link

@hiragram hiragram commented Nov 17, 2025

fixes: #1604

This PR fixes a regression in JSONDecoder where attempting to decode incompatible numeric values (e.g., decimal 123.45 as Int, or negative -123 as UInt) returns incorrect error information. The bug affects both the codingPath (empty instead of correct path) and debugDescription (generic message instead of specific error details).

See more detail: #1604

…iftlang#1604)

This commit fixes the regression where JSONDecoder returns incorrect error
information when attempting to decode a decimal value (e.g., 123.45) as Int.

**Root Cause (from git history investigation):**
- Initial implementation (commit 34c45c1, 2023-03-15) had correct error handling
- BufferView refactoring (commit 1ab3832, 2023-04-03) accidentally removed the
  proper DecodingError.dataCorrupted throw statements
- This caused JSONError.numberIsNotRepresentableInSwift to be caught at the
  top level and converted to a generic error with empty codingPath

**Changes:**
- Restored proper error handling in `_slowpath_unwrapFixedWidthInteger`
- Changed JSONError.numberIsNotRepresentableInSwift throws to
  DecodingError.dataCorrupted with correct codingPath and debugDescription
- Added regression test to prevent future breakage

**Before (broken):**
- codingPath: [] (empty)
- debugDescription: "The given data was not valid JSON."

**After (fixed):**
- codingPath: ["foo"]
- debugDescription: "Parsed JSON number <123.45> does not fit in Int."

Fixes swiftlang#1604
Related: swiftlang#274
@omochi
Copy link

omochi commented Nov 18, 2025

@swift-ci please test

static private func _slowpath_unwrapFixedWidthInteger<T: FixedWidthInteger>(as type: T.Type, json5: Bool, numberBuffer: BufferView<UInt8>, fullSource: BufferView<UInt8>, digitBeginning: BufferViewIndex<UInt8>, for codingPathNode: _CodingPathNode, _ additionalKey: (some CodingKey)?) throws -> T {
// Helper function to create number conversion error
func createNumberConversionError() -> DecodingError {
#if FOUNDATION_FRAMEWORK
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think we need to preserve this existing (broken) behavior for FOUNDATION_FRAMEWORK as long as underlyingError's error code is untouched... @kperryua what do you think?

Copy link
Author

Choose a reason for hiding this comment

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

@itingliu Thanks for your review. Just to confirm, are you saying that underlyingError should always be
nil on all platforms in this case?

There is existing code that switches the presence of underlyingError based on the FOUNDATION_FRAMEWORK flag, which I used as a reference. I don't fully understand the intent behind it, but I think it would be better to keep the behavior consistent.

https://github.com/hiragram/swift-foundation/blob/fix-jsondecoder/Sources/FoundationEssentials/JSON/JSONDecoder.swift#L388-L393

@itingliu
Copy link
Contributor

@swift-ci please test

@itingliu itingliu closed this Nov 30, 2025
@itingliu itingliu reopened this Nov 30, 2025
@itingliu
Copy link
Contributor

Sorry, I meant to click "comment" but clicked "close" accidentally.

@itingliu
Copy link
Contributor

@swift-ci please test

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.

JSONDecoder throws a broken error when parsing decimal value as Int

3 participants