How to fix Error 347 on Windows Server 2025 / Windows 11

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 OUTPUT keyword immediately following the parameter’s data type declaration.
  • Ensure the READONLY keyword 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 ... SELECT statement 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 SqlCommand object to remove the ParameterDirection.Output property associated with the TVP’s SqlParameter.
  • Change the execution logic to capture results via SELECT statements or a secondary SELECT * 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 PROCEDURE command 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 MERGE statement with an OUTPUT INTO clause to capture affected rows into a physical logging table instead of relying on the parameter itself.