Microsoft SQL Server 2025 Troubleshooting Guide: Error 347
Error Message: “The table-valued parameter “%.*ls” cannot be declared as an OUTPUT parameter.”
Applies To: Microsoft SQL Server 2025 on Windows Server 2025 / Windows 11
Why This Error Happens
This error occurs because Table-Valued Parameters (TVPs) are read-only by design in the SQL Server Database Engine, regardless of the version or OS hosting it. Developers migrating stored procedures or converting legacy dynamic SQL often mistakenly attempt to append the OUTPUT keyword to a TVP declaration, assuming it behaves like a standard scalar parameter (e.g., INT or VARCHAR). Since the engine has no internal mechanism to write modified row sets back through a TVP, the parser immediately rejects the batch with Error 347 before compilation can proceed.
Step-by-Step Resolution Guide
Step 1: Identify and Remove the Invalid OUTPUT Keyword
- Open the stored procedure or function definition in SQL Server Management Studio (SSMS) 21 or Azure Data Studio.
- Locate the parameter declaration matching the pattern:
@YourTVP dbo.YourTableType READONLY OUTPUT. - Delete the
OUTPUTkeyword immediately following the parameter’s data type declaration. - Ensure the
READONLYkeyword remains, as this is mandatory for all TVPs.
Step 2: Refactor the Logic to Use a Standard Table Variable or Temp Table
- Since you cannot pass data out via a TVP, declare a local table variable (e.g.,
DECLARE @ResultSet TABLE (...)) inside the procedure body. - Alternatively, use a global temporary table (
##TempResults) if the data needs to persist across sessions on the Windows Server 2025 instance. - Populate this new table using an
INSERT INTO ... SELECTstatement based on the logic you originally intended for the output.
Step 3: Update the Application Calling Code
- If a .NET or Python application on Windows 11 is calling this procedure, modify the
SqlCommandobject to remove theParameterDirection.Outputproperty associated with the TVP’sSqlParameter. - Change the execution logic to capture results via
SELECTstatements or a secondarySELECT * FROM @ResultSet;at the end of the stored procedure, treating the output as a standard result set rather than a parameter.
Step 4: Recompile and Deploy the Procedure
- Execute an
ALTER PROCEDUREcommand to push the corrected syntax to the SQL Server 2025 instance. - Clear the procedure cache for the specific object using
DBCC FREEPROCCACHE (plan_handle)to ensure no old, invalid execution plans are cached.
Alternative or Verification Steps
- Verification: Run the modified stored procedure directly in a new SSMS query window using
EXEC dbo.YourProcName @TVP = @YourVariable;and confirm the result grid populates correctly without throwing Error 347. - Alternative: If the application architecture strictly requires “output” style bulk data transfer, use a
MERGEstatement with anOUTPUT INTOclause to capture affected rows into a physical logging table instead of relying on the parameter itself.