Sharepoint: How to fix Invalid postback or callback argument.

Yesterday I have one of those issues that without some kind of experience will make your head hit through walls, it was really difficult to find.

On one NEW web application, which had no WSPs installed and where there was a site collection without custom master pages created.

So everything was out of the box, everything.

The user had 2 webparts visible, they were list viewwebparts, and there was a content section at the top, everytime they tried to save or do a POST request, on any part of the site, they got this error:

Invalid postback or callback argument. Event validation is enabled using in configuration or <%@ Page EnableEventValidation="true" %> in a page. For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them. If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation.

When researching on the web, we didnt find any clue about why this happened on Sharepoint, there were lots of blog posts and forums but related to ASP.NET, not in the context of Sharepint, and one of the solutions was to disable ClientValidation, which would make the site vulnerable to injection attacks.

Then I check the ULS logs, nothing appeared, checked the EventLogs and there was nothing as well, damn it.

Next what I did is to take one of the pages and append ?Contents=1, in this way I could see the Maintenance page for that page.

Surprise, there were 3 webparts, but only 2 were visible, so One was not working.

When I clicked on one of those to restore it, I got this other exception:

Validation of viewstate MAC failed. If this application is hosted by a Web Farm or cluster, ensure that configuration specifies the same validationKey and validation algorithm. AutoGenerate cannot be used in a cluster.

Then things started to make sense, this is a 2 server farm with a load balancer in front of these.

The problem is that there has to be a machinekey element on the web.config for that web application, the machinekey has to be the same for both servers, this key is used by Sharepoint to encrypt information, and if they are not the same, then the round robin algorithm from the load balanced will send you to different servers each time, therefore not able to respond correctly.

In order to resolve this, you have to add the machinekey under system.web on web.config, and to generate it, just use this powershell

# Generates a <machineKey> element that can be copied + pasted into a Web.config file.
function Generate-MachineKey {  
  [CmdletBinding()]
  param (
    [ValidateSet("AES", "DES", "3DES")]
    [string]$decryptionAlgorithm = 'AES',
    [ValidateSet("MD5", "SHA1", "HMACSHA256", "HMACSHA384", "HMACSHA512")]
    [string]$validationAlgorithm = 'HMACSHA256'
  )
  process {
    function BinaryToHex {
        [CmdLetBinding()]
        param($bytes)
        process {
            $builder = new-object System.Text.StringBuilder
            foreach ($b in $bytes) {
              $builder = $builder.AppendFormat([System.Globalization.CultureInfo]::InvariantCulture, "{0:X2}", $b)
            }
            $builder
        }
    }
    switch ($decryptionAlgorithm) {
      "AES" { $decryptionObject = new-object System.Security.Cryptography.AesCryptoServiceProvider }
      "DES" { $decryptionObject = new-object System.Security.Cryptography.DESCryptoServiceProvider }
      "3DES" { $decryptionObject = new-object System.Security.Cryptography.TripleDESCryptoServiceProvider }
    }
    $decryptionObject.GenerateKey()
    $decryptionKey = BinaryToHex($decryptionObject.Key)
    $decryptionObject.Dispose()
    switch ($validationAlgorithm) {
      "MD5" { $validationObject = new-object System.Security.Cryptography.HMACMD5 }
      "SHA1" { $validationObject = new-object System.Security.Cryptography.HMACSHA1 }
      "HMACSHA256" { $validationObject = new-object System.Security.Cryptography.HMACSHA256 }
      "HMACSHA385" { $validationObject = new-object System.Security.Cryptography.HMACSHA384 }
      "HMACSHA512" { $validationObject = new-object System.Security.Cryptography.HMACSHA512 }
    }
    $validationKey = BinaryToHex($validationObject.Key)
    $validationObject.Dispose()
    [string]::Format([System.Globalization.CultureInfo]::InvariantCulture,
      "<machineKey decryption=`"{0}`" decryptionKey=`"{1}`" validation=`"{2}`" validationKey=`"{3}`" />",
      $decryptionAlgorithm.ToUpperInvariant(), $decryptionKey,
      $validationAlgorithm.ToUpperInvariant(), $validationKey)
  }
}

Generate-MachineKey -validation sha1