This is very confusing.
In a nutshell, you can create temp tables with the same name if you create them in different scopes. If you create #temp in both inner_sp and outer_sp, the #temp in inner_sp will hide the one created in outer_sp, but not until #temp in inner_sp has been created.
This is confusing enough, but due to that SQL Server cache query plans, you can also get very inconsistent results. This runs:
CREATE PROCEDURE inner_sp AS
CREATE TABLE #temp(b int NOT NULL)
SELECT b FROM #temp
go
EXEC inner_sp
go
CREATE PROCEDURE outer_sp AS
CREATE TABLE #temp(a int NOT NULL)
SELECT a FROM #temp
EXEC inner_sp
go
EXEC outer_sp
This works, because when outer_sp calls inner_sp, there is already a plan for inner_sp in the cache.
But if you now run:
ALTER PROCEDURE inner_sp AS
CREATE TABLE #temp(b int NOT NULL)
SELECT b FROM #temp
go
EXEC outer_sp
You get this error:
Msg 207, Level 16, State 1, Procedure inner_sp, Line 3 [Batch Start Line 127] Invalid column name 'b'.
Because inner_sp was recompiled, the plan is no longer in the cache. When outer_sp calls inner_sp, the procedure has to be compiled. But it is compiled against the definition from outer_sp.
To avoid this confusion, don't use names like #temp etc, but give your temp tables distinct names.