Fix Error Msg 6825 “ELEMENTS option is only allowed in RAW, AUTO, and PATH modes of FOR XML” in SQL Server

If you’re getting error msg 6825 that reads “ELEMENTS option is only allowed in RAW, AUTO, and PATH modes of FOR XML“, it’s probably because you’re trying to use the ELEMENTS directive while using EXPLICIT mode of the FOR XML clause.

As the message alludes to, this option is not available when using the EXPLICIT mode (it’s only allowed with the RAW, AUTO, and PATH modes).

However, SQL Server does provide us with an equivalent that provides the same result. When using EXPLICIT mode, we can use the ELEMENT directive instead. We apply this to the column names, instead of the end of the query. We can alternatively use the ELEMENTXSINIL directive to ensure that elements are generated even if the column contains a NULL value.

Example of Error

Here’s an example of code that produces the error:

SELECT
    1 AS Tag,
    NULL AS Parent,
    p.PetId AS [Pet!1!PetId],
    NULL AS [Details!2!PetName],
    NULL AS [Details!2!PetType]
FROM Pets p 
    INNER JOIN PetTypes pt ON p.PetTypeId = pt.PetTypeId
UNION ALL
SELECT
    2 AS Tag,
    1 AS Parent,
    p.PetId,
    p.PetName,
    pt.PetType
FROM Pets p 
    INNER JOIN PetTypes pt ON p.PetTypeId = pt.PetTypeId
ORDER BY [Pet!1!PetId], [Details!2!PetName]
FOR XML EXPLICIT, ELEMENTS;

Result:

Msg 6825, Level 16, State 1, Line 10
ELEMENTS option is only allowed in RAW, AUTO, and PATH modes of FOR XML.

The reason I got the error is because I used the ELEMENTS directive instead of the ELEMENT directive.

Solution

The solution to the above issue is to use the ELEMENT directive instead of the ELEMENTS directive:

SELECT
    1 AS Tag,
    NULL AS Parent,
    p.PetId AS [Pet!1!PetId],
    NULL AS [Details!2!PetName!ELEMENT],
    NULL AS [Details!2!PetType!ELEMENT]
FROM Pets p 
    INNER JOIN PetTypes pt ON p.PetTypeId = pt.PetTypeId
UNION ALL
SELECT
    2 AS Tag,
    1 AS Parent,
    p.PetId,
    p.PetName,
    pt.PetType
FROM Pets p 
    INNER JOIN PetTypes pt ON p.PetTypeId = pt.PetTypeId
ORDER BY [Pet!1!PetId], [Details!2!PetName!ELEMENT]
FOR XML EXPLICIT;

Result:

<Pet PetId="1">
	<Details>
		<PetName>
			Fluffy
		</PetName>
		<PetType>
			Cat
		</PetType>
	</Details>
</Pet>
<Pet PetId="2">
	<Details>
		<PetName>
			Fetch
		</PetName>
		<PetType>
			Dog
		</PetType>
	</Details>
</Pet>
<Pet PetId="3">
	<Details>
		<PetName>
			Scratch
		</PetName>
		<PetType>
			Cat
		</PetType>
	</Details>
</Pet>

When using the ELEMENT directive, we need to add it to the individual columns that we want to be elements. In the above example I added !ELEMENT to two columns, but left the PetId column as an attribute.

Dealing with NULL Values

When using the ELEMENT directive, if a column contains a NULL value, an element is not generated. If we want an element to be generated for NULL values, we can use the ELEMENTXSINIL directive instead of ELEMENT.