question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Powershell Core deserializes numbers in JSON as Int64 vs Windows Powershell which does it as Int32

See original GitHub issue

This is actually a copy of the StackOverflow issue with the same name from @Mark: Powershell Core deserializes numbers in JSON as Int64 vs Windows Powershell which does it as Int32

Steps to reproduce

$a = "1" | ConvertFrom-Json
(@{ $a = 2 }).1

Expected behavior

Return 2 (just like Windows PowerShell 5)

Actual behavior

Returns nothing (because the actual key is of type [Int64] and the key “.1” of type [Int32])

I am not sure whether this can be called a bug or is “by design” but my expectation (from a dynamically typed language as PowerShell Core) is that a Json number (less then [int]::MaxValue) should default to an [Int32] type, just like:

$a = 1
$a.GetType().Name
Int32

Workarround

Recast the number:

$a = "1" | ConvertFrom-Json
$a = 0 + "$a"
(@{ $a = 2 }).1
2

related:

Environment data

Name                           Value
----                           -----
PSVersion                      7.1.0
PSEdition                      Core
GitCommitId                    7.1.0
OS                             Microsoft Windows 10.0.19042
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:2
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
mklement0commented, Nov 27, 2020

“This conversion from to / from text serialization format changes type X to type Y”

The problem is that JSON is an invariably “lossy” serialization format with .NET types as the input. You lose the specific number types, as any number in JSON becomes that abstraction: a JSON primitive of kind Number. Similarly, JSON has no [char] type, only String.

Therefore, no one should expect a round trip to work.

However, it is reasonable to expect from-JSON conversion to expect PowerShell-typical behavior, which to me means performing the automatic type-widening as needed, the same way that (non-type-letter-suffixed) number literals in PowerShell source code employ, which means: [int] as the smallest type -> [long] -> [decimal] -> [double].

(On a related note: going from [decimal] to [bigint] before going to [double] in number-literal parsing would make sense, to avoid quiet loss of accuracy - see #13212; by contrast, ConvertFrom-Json in PS Core currently skips the [decimal] step and goes straight from [long] to [bigint] - see https://github.com/PowerShell/PowerShell/issues/9207#issuecomment-573992565) - whereas Windows PowerShell tops out at [double] beyond [decimal], and never uses [bigint].

I suspect to avoid a test to say "Does this need to be an int64 ?

Yes, as implied by a quote of the author of the Json.NET library underlying the current ConvertFrom-Json from the SO answer that @iRon7 links to in the OP:

Json.NET by default reads integer values as Int64 because there is no way to know whether the value should be Int32 or Int64, and Int64 is less likely to overflow. For a typed property the deserializer knows to convert the Int64 to a Int32 but because your property is untyped you are getting an Int64.

0reactions
LaurentDardennecommented, Aug 15, 2022

The use of

   ...|Convert-From | Group-Object -Property XYZ -AsHashTable

may in some cases require an adaptation of the code depending on the version of powershell.

Example :

$Runs=( gh api -H "Accept: application/vnd.github+json" /repos/OWNER/REPO/actions/runs|ConvertFrom-Json).workflow_runs|
     Group-Object workflow_id -AsHashTable

$List=$runs.GetEnumerator()|% {$_}
$List[0].Key.GetType()

If I have to search for a key, from a cast of a string, the code differs.

$id='1234'

#v5.1
$runs.ContainsKey($id -as [int32])

#Core
$runs.ContainsKey($id -as [int64])

Shouldn’t this post be marked as ‘Breaking change’ ?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Powershell Core deserializes numbers in JSON as Int64 vs ...
Windows PowerShell uses a custom implementation, whereas PowerShell [Core] v6+, as of v7.1, uses the Json.NET library behind the scenes; see ...
Read more >
Invoke-RestMethod - PowerShell
The Invoke-RestMethod cmdlet sends HTTP and HTTPS requests to Representational State Transfer (REST) web services that return richly structured data.
Read more >
Understanding Numbers in PowerShell - Scripting Blog
There are actually three numeric types that Windows PowerShell uses: Decimal types; Integral types; Floating-point types. Decimal types.
Read more >
ConvertTo-Json - PowerShell
The ConvertTo-Json cmdlet converts any .NET object to a string in JavaScript Object Notation (JSON) format. The properties are converted to field names, ......
Read more >
JavaScriptSerializer Class (System.Web.Script.Serialization)
Therefore, you can use the class when you want to work with JavaScript Object Notation (JSON) in managed code. To serialize an object,...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found