Skip to content
Microsoft SQL Server

SQL Server Error 134

The variable name has already been declared

Applies to: All supported SQL Server versions (2016 to 2025), Azure SQL Database, Azure SQL Managed Instance
Last technically reviewed 24 October 2026 on SQL Server 2025 (17.0.1145.4)
The full message
Msg 134, Level 15, State 1, Line 1
The variable name '@total' has already been declared. Variable names must be unique within a query batch or stored procedure.
Other forms of this message
Names that differ only in case, on a case-insensitive instance (reproduced)
Msg 134, Level 15, State 1, Line 1
The variable name '@TOTAL' has already been declared. Variable names must be unique within a query batch or stored procedure.
Error number
134
Severity
15 (user-correctable error)
State
1
Product
Microsoft SQL Server Database Engine
Versions
All supported SQL Server versions (2016 to 2025), Azure SQL Database, Azure SQL Managed Instance
Last reviewed
24 October 2026

What it means

Error 134 means the same @variable name is declared twice in one batch or one procedure, which T-SQL does not allow because a variable lives for the whole batch, not for the block it is declared in.

In T-SQL the scope of a local variable is the whole batch (or the whole body of a procedure, function or trigger) from the DECLARE onwards. BEGIN ... END, IF, ELSE and WHILE do not open a new scope, unlike in C# or Java. So two DECLAREs of the same name anywhere in one batch collide, even when one is inside a loop or a branch that would never run. The parser rejects the batch with 134 at severity 15 before any statement executes, and names the second declaration.

Procedure parameters count as declarations too, so DECLARE @rate in a procedure that already has a @rate parameter fails the same way. Splitting a script with GO ends the batch and its variables, which is why a duplicate name is fine across batches, and why the opposite mistake, using a variable after GO, raises error 137.

Common causes

  • Two script snippets pasted into one batch, each with its own DECLARE @total.
  • A DECLARE inside a WHILE loop or IF block for a name already declared earlier in the batch, on the assumption that blocks have their own scope.
  • The same variable declared in both the IF and the ELSE branch.
  • A procedure body that declares a variable with the same name as one of its parameters.
  • Names that differ only in case, such as @Total and @TOTAL, on an instance with a case-insensitive collation.

Diagnose it

Read-only These queries only read metadata and dynamic management views. They do not change data, permissions or configuration, so they are safe to run first.

Check a corrected batch compiles without running it

sp_describe_first_result_set parses and binds the batch it is given and reports 134 if a name is still declared twice, without executing anything.

EXEC sp_describe_first_result_set
     N'DECLARE @total int = 0;
       SET @total = @total + 5;
       SELECT @total AS total;';
What to look for

One row describing the total column. Error 134 instead means a duplicate DECLARE remains.

List the parameters an existing procedure already declares

When an ALTER PROCEDURE fails with 134, compare the names you DECLARE in the body with the parameter names.

SELECT p.parameter_id, p.name AS parameter_name, TYPE_NAME(p.user_type_id) AS data_type
FROM sys.parameters AS p
WHERE p.object_id = OBJECT_ID(N'dbo.ApplyDiscount')
ORDER BY p.parameter_id;
What to look for

Every name listed here is already declared inside the procedure body; a DECLARE with the same name raises 134.

How to fix it

Each fix is labelled with what it changes. Try read-only checks and the least invasive fix first, and test changes outside production.

Declare once at the top, assign with SET later

Read-only

Keep one DECLARE per name, at the start of the batch, and use SET or SELECT to give it new values. Inside a loop, reset it explicitly at the start of each pass.

DECLARE @i int = 1, @msg varchar(20);
WHILE @i <= 3
BEGIN
    SET @msg = 'row ' + CAST(@i AS varchar(5));   -- assign, do not redeclare
    PRINT @msg;
    SET @i += 1;
END;

Give the second variable its own name

Read-only

When the two declarations really hold different things (an order total and an invoice total), name them after what they hold.

DECLARE @order_total decimal(10,2) = 0;
DECLARE @invoice_total decimal(10,2) = 0;

Split independent snippets with GO

Client or network side

If the snippets are independent, end each batch with GO in SSMS or sqlcmd. Each batch then gets its own variables. Do not do this when a later part still needs the earlier values.

DECLARE @total int = 0;
SELECT @total AS first_total;
GO
DECLARE @total int = 5;
SELECT @total AS second_total;

In a procedure, use the parameter instead of redeclaring it

Changes schema

Assign a default to the parameter with SET or ISNULL instead of declaring a variable with the same name.

CREATE OR ALTER PROCEDURE dbo.ApplyDiscount
    @order_id int,
    @rate decimal(4,2) = NULL
AS
BEGIN
    SET @rate = ISNULL(@rate, 0.10);
    SELECT @order_id AS order_id, @rate AS rate;
END;

Examples

Two snippets pasted into one batch

DECLARE @total int = 0;
SELECT @total AS order_count;

DECLARE @total int = 5;   -- second snippet, same name
SELECT @total AS invoice_count;
Result
Msg 134, Level 15, State 1, Line 4
The variable name '@total' has already been declared. Variable names must be unique within a query batch or stored procedure.

Reproduced on SQL Server 2025 (17.0.1145.4), 23 October 2026.

A DECLARE inside a loop for a name declared earlier

DECLARE @i int = 1;
DECLARE @msg varchar(20);
WHILE @i <= 3
BEGIN
    DECLARE @msg varchar(20) = 'row';   -- a loop is not a new scope
    SET @i += 1;
END;
Result
Msg 134, Level 15, State 1, Line 5
The variable name '@msg' has already been declared. Variable names must be unique within a query batch or stored procedure.

Reproduced on SQL Server 2025 (17.0.1145.4), 23 October 2026.

A procedure that redeclares its own parameter

CREATE PROCEDURE dbo.ApplyDiscount @order_id int, @rate decimal(4,2)
AS
    DECLARE @rate decimal(4,2) = 0.10;   -- @rate is already a parameter
    SELECT @order_id AS order_id, @rate AS rate;
Result
Msg 134, Level 15, State 1, Procedure ApplyDiscount, Line 3
The variable name '@rate' has already been declared. Variable names must be unique within a query batch or stored procedure.

Reproduced on SQL Server 2025 (17.0.1145.4), 23 October 2026.

How to prevent it

Declare all variables of a batch or procedure in one block at the top, with names that say what they hold. That makes duplicates obvious in review and avoids the loop trap: a DECLARE without a value inside a WHILE loop does not reset the variable on the next pass, so the old value leaks into the next iteration.

When you assemble scripts from several files, keep each file as its own batch ending in GO. For more on how batches, procedures and variables fit together, see stored procedures and functions.

Common questions

Can I declare a variable inside a WHILE loop?

Yes, once per batch. The DECLARE is processed at compile time, so the variable exists for the whole batch, and a DECLARE without a value does not reset it on each pass. Set it explicitly at the start of the loop body.

Why does declaring the same variable in IF and in ELSE fail?

IF and ELSE do not create scopes in T-SQL. Both DECLAREs are in the same batch, so the second one raises 134 even though only one branch can run.

What is the difference between error 134 and error 137?

Error 134 is a name declared twice in one batch. Error 137 is a name used without being declared in the current batch, often because a GO ended the batch that declared it.

Learn more on CodeWithSQL

Official documentation

Last technically reviewed 24 October 2026; examples and diagnostics run on SQL Server 2025 (17.0.1145.4). Message text checked against the engine's sys.messages catalogue.

Still stuck on a SQL Server error?

Browse the full SQL Server error library, or get hands-on help from an experienced SQL professional.