What are some sources of: MSI error 2716: "Could not create a random subcomponent name for component '[2]'".?

Question

Background

For background on subcomponents, see Why does the Windows Installer log list apparently duplicate components prepended with double underscore and appended with 65?

A careful reader will notice a problem with the subcomponent generation algorithm. See it? It's the component name is based off the first 40 characters of the component. What happens if the the first 40 characters of all the components in a package are identical?

The Windows Installer has code to look for collisions and increment an index until one is not found. Turns out there's a arbritary limit of 100 iterations of that loop.

Troubleshooting Package

Here's why the simplified repro package suffers from the problem

You have 74 components in the Component table in this package. Of those 74 components, 70 have the same 41 character prefix: PUBLIC_HIDEAPP_OAK_LIB_MIPSIV_FP_RETAIL__. What we're hitting here is the MaxTry limitation. In the installation package, there are three tables that result in cost-linking: Shortcut, IniFile, & MoveFile. The Shortcut table can be ignored because it doesn't use one of the 70 components with the same 41 character prefix. The IniFile and MoveFile tables are important.

Starting with the IniFile table: There are 35 components of the 70 that are listed in the table. Each component ends up being cost-linked to two directories. That means that two temp components are created for each component in the table. So, we have cost-linking of the component to the CRC directory and cost-linking of the Component to the WindowsFolder directory. Even with the child component account, you'll still start to hit a problem. (Each component will end up with 1 child component after the first run of cost-linking the CRC component).

By the end of this, we've used up 70 cost-link names. We only have about 100 available because of the MaxTries amount and the fact that only the first 40 characters are chosen. So we have temp components:

     __PUBLIC_HIDEAPP_OAK_LIB_MIPSIV_FP_RETAIL_65
    __PUBLIC_HIDEAPP_OAK_LIB_MIPSIV_FP_RETAIL_66
    ...
    __PUBLIC_HIDEAPP_OAK_LIB_MIPSIV_FP_RETAIL_135

Now we move on to the MoveFile table. There's a possibility of two cost-linked components created per row. However, the source and destination folders in this package authoring are the same, so there'll only be one cost-linked component per row. Note that the directory used here was not one that was used in the IniFile table (if it was, we wouldn't need to create a new cost-linked component for it). There are 35 rows reprsented in the MoveFile table for these 70 components. That makes 35 more temporary components that have to be created since all of the rows represent unique components and new directories.

Well, now we've hit the 100 limit. 70 + 35 = 105 so we bomb out for the temp component creation. This cost-linking starts at:

     __PUBLIC_DIRECTX_OAK_LIB_MIPSIV_FP_RETAIL_136
    ...
    __PUBLIC_DIRECTX_OAK_LIB_MIPSIV_FP_RETAIL_165
    __PUBLIC_DIRECTX_OAK_LIB_MIPSIV_FP_RETAIL_166  // FAILURE! 

It fails at suffix 166 because it's already exhausted the max tries value.

Normally this isn't a problem because you don't usually hit the subcomponent name limitation. Most component names differ within the first 40 characters, and even if not, there aren't enough similarities to hit the iMaxTries upper limit. It just so happens that this is the case with the way these packages are built. If you guarantee uniqueness within the first 40 characters of all components, you won't have any issues.

What you'd normally expect to see would be something like the following if your components didn't include that same 41 character prefix:

 IniFile table results:
    __MSGSNET___PDB65    (cost-link for WindowsFolder)
    __MSGSNET___PDB66    (cost-link for CRC)
    __MSMSGS___LIB65         (cost-link for WindowsFolder)
    __MSMSGS___LIB66         (cost-link for CRC)
    __MSMSGS___PDB65       (cost-link for WindowsFolder)
    __MSMSGS___PDB66       (cost-link for CRC)
    __MSMSGS_QVGA___LIB65 (cost-link for WindowsFolder)
    __MSMSGS_QVGA___LIB66 (cost-link for CRC)
    ...
 
 MoveFileTable results:
    __DSRTP___LIBB65 (cost-link for PUBLIC_HIDEAPP_OAK_LIB_MIPSIV_FP_RETAIL__DSRTP___LIB)
    __DYNDLL___PDBB65 (cost-link for PUBLIC_HIDEAPP_OAK_LIB_MIPSIV_FP_RETAIL__DYNDLL___PDB)
    ...
 

But because you have the same 40 characters in your package (actually 41), you end up with all of the collissions and end up maxing out because you hit the upper limit for subcomponent name generation.

If you want to make your packages work, you'll need to alter your component name generation. In particular, ensure that the first 40 characters are unique.

Content credit also belongs to

[Author: Robert Flaming]

This posting is provided "AS IS" with no warranties, and confers no rights. Use of included script samples are subject to the terms specified at https://www.microsoft.com/info/cpyright.htm.