MSRM Release fails in Predeploy stage with 404 Not Found

I recently encountered a situation in MS Release Management where adding an additional component to my release template would cause any Release based on it to get rejected in the Predeploy stage with a rather cryptic “(404) Not Found.”

What was strange was that the component itself was perfectly fine, and would deploy OK if used in another Release template. After a little trial and error, I figured out that it wasn’t the component itself, but the number of components used in the Release template that caused the Release to get rejected: In my case, a Release with any 5 components would deploy fine, but would get rejected as soon as I added a 6th component.
I’m using MS Release Management Update 4.

Release rejected in Predeploy

Pinpointing the problem

Because the 404 didn’t make much sense to me, I tried to enable various forms of logging on MS Release Management (see one of my earlier posts for an overview).
Most of these didn’t turn up anything useful, but then I enabled logging of the System.Net.Sockets tracesource on the Release Management services by adding the following section to the Release Managementservicesweb.config file:

  <system.diagnostics>
    <trace autoflush=&quot;true&quot;/>
    <sources>
      <source name=&quot;System.Net.Sockets&quot; maxdatasize=&quot;10240&quot;>
        <listeners>
          <add name=&quot;socketListener&quot;/>
        </listeners>
      </source>
    </sources>
    <switches>
      <add name=&quot;System.Net.Sockets&quot; value=&quot;Verbose&quot;/>
    </switches>
    <sharedListeners>
      <add name=&quot;socketListener&quot;
           type=&quot;System.Diagnostics.TextWriterTraceListener&quot;
           initializeData=&quot;C:LogsReleaseManagementServices-network.log&quot; />
    </sharedListeners>
  </system.diagnostics>

This effectively causes all network traffic to and from MSRM’s webservices to be written to a logfile – in a rather unpractical format, but it does the trick. When trying (and failing) to deploy the Release once more, the logfile now contains a message that brings us closer to the origin of the problem:

<div class=&quot;content-container&quot;>
  <h3>HTTP Error 404.15 - Not Found</h3>
  <h4>The request filtering module is configured to deny a request where the query string is too long.</h4>
</div>

Apparently, MSRM passes the locations of the components that are to be deployed to a REST api, but does so using the query string. For example, this is (just) the query string for request that triggered the 404 error in my case (I added line breaks for readability):

POST /account/releaseManagementService/_apis/releaseManagement/OrchestratorService/PreDeployComplete
  ?releaseId=125&releaseStepId=560
  &isSuccess=True
  &normalizedStore=%3CArrayOfNormalizedStoreDetail%20%20%3E%0D%0A
    %20%20%3CNormalizedStoreDetail%20PackageLocation=%22rmserver.corporate.mycompany.comStagingAcmev2.3%20build%202290/Customizations%5C%22%20ComponentId=%22419%22%20UploadLocation=%22rmserver.corporate.mycompany.comStagingAcmev2.3%20build%202290/Customizations%5C%22%20NetworkType=%22Trusted%22%20/%3E%0D%0A
    %20%20%3CNormalizedStoreDetail%20PackageLocation=%22rmserver.corporate.mycompany.comStagingAcmev2.3%20build%202290/Plugins%20and%20workflow%20activities%5C%22%20ComponentId=%22420%22%20UploadLocation=%22rmserver.corporate.mycompany.comStagingAcmev2.3%20build%202290/Plugins%20and%20workflow%20activities%5C%22%20NetworkType=%22Trusted%22%20/%3E%0D%0A
    %20%20%3CNormalizedStoreDetail%20PackageLocation=%22rmserver.corporate.mycompany.comStagingAcmev2.3%20build%202290/Workflows%5C%22%20ComponentId=%22421%22%20UploadLocation=%22rmserver.corporate.mycompany.comStagingAcmev2.3%20build%202290/Workflows%5C%22%20NetworkType=%22Trusted%22%20/%3E%0D%0A
    %20%20%3CNormalizedStoreDetail%20PackageLocation=%22rmserver.corporate.mycompany.comStagingAcmev2.3%20build%202290/CustomUIParts%5C%22%20ComponentId=%22422%22%20UploadLocation=%22rmserver.corporate.mycompany.comStagingAcmev2.3%20build%202290/CustomUIParts%5C%22%20NetworkType=%22Trusted%22%20/%3E%0D%0A
    %20%20%3CNormalizedStoreDetail%20PackageLocation=%22rmserver.corporate.mycompany.comStagingAcmev2.3%20build%202290/Backup%20Acme%20Databases%5C%22%20ComponentId=%22423%22%20UploadLocation=%22rmserver.corporate.mycompany.comStagingAcmev2.3%20build%202290/Backup%20Acme%20Databases%5C%22%20NetworkType=%22Trusted%22%20/%3E%0D%0A
    %20%20%3CNormalizedStoreDetail%20PackageLocation=%22rmserver.corporate.mycompany.comStagingAcmev2.3%20build%202290/Backup%20Acme%20Components%5C%22%20ComponentId=%22424%22%20UploadLocation=%22rmserver.corporate.mycompany.comStagingAcmev2.3%20build%202290/Backup%20Acme%20Components%5C%22%20NetworkType=%22Trusted%22%20/%3E%0D%0A
    %3C/ArrayOfNormalizedStoreDetail%3E
  &api-version=3.0

No wonder that the “query string is too long” when each referenced component adds some 300 characters to it and IIS considers (by default) a query string of more than 2048 characters “too long”. Granted, when using FQDNs and/or long component names you’ll hit this limit faster, but even when you don’t do these things, referencing too many components will trigger the 404 – Not found.

Increasing the maximum query string length

Now that we know the cause of the problem, we can compensate for it. One way is simply using shorter server and/or component names, but assuming that you can’t or don’t want to change these, we can also tell IIS to accept longer query strings. An easy way of doing this is by modifying the Release Managementservicesweb.config file.
This has to be done in 2 places, both at the IIS level through the requestLimits element and at the ASP.NET level via the httpRuntime element.

In other words, make sure that the web.config contains the following fragments:

  <system.webServer>
    <security>
      <requestFiltering>
         <requestLimits maxQueryString=&quot;4096&quot; />
      </requestFiltering>
    </security>
  </system.webServer>

  <system.web>
    <httpRuntime
    	executionTimeout=&quot;300&quot;
    	maxRequestLength=&quot;409600&quot;
    	maxQueryStringLength=&quot;4096&quot;
    	targetFramework=&quot;4.5&quot; />
  </system.web>

After restarting the ReleaseManagementAppPool, these settings should take effect and the Release should no longer be rejected.

Cheers!