Trying to drop database only if it does not exist by using the db_id function fails When the database foo is not yet created and I I run this

IF db_id(N'foo') IS NOT NULL
BEGIN
  ALTER DATABASE [foo] SET OFFLINE
  GO

  DROP DATABASE [foo]
  GO
END


I get a message


  Cannot drop the database 'foo' becuase it does not exist or you do not
  have permission.


Why?

I have confirmed that the sql statement select db_id(N'foo') returns NULL.
This is a parsing error, not a runtime error. You can avoid this by removing the GO commands (these can't exist inside an IF block anyway) and using dynamic SQL. 

Why IF DB_ID() instead of just putting the DROP inside TRY/CATCH (or letting it error)?

You may want WITH ROLLBACK IMMEDIATE on the ALTER.

BEGIN TRY
  ALTER DATABASE foo SET OFFLINE WITH ROLLBACK IMMEDIATE;
  DROP DATABASE foo;
END TRY
BEGIN CATCH
  PRINT 'Failure or database does not exist.';
END CATCH


Or

IF DB_ID(N'foo') IS NOT NULL
BEGIN
  EXEC sys.sp_executesql N'ALTER DATABASE foo SET OFFLINE WITH ROLLBACK IMMEDIATE;
    DROP DATABASE foo;';
END


Of course this approach (OFFLINE first) will leave the data and log files intact, which means that if they were created in the default location, if you try to create the same database again, you'll first need to move or rename those files, or manually specify different names in the new file specification.