On a SQL 2016 CTP 3.2 server I was writing PowerShell scripts to bulk copy data into a database with simple ADO.NET classes. It was working perfectly fine to start with.

$bulkCopy = New-Object System.Data.SqlClient.SqlBulkCopy($bulkCopyConnection, [System.Data.SqlClient.SqlBulkCopyOptions]::Default, $bulkCopyTransaction)

foreach ($table in $dataSet.Tables) {
    Write-Verbose "Saving $($table.TableName)"
    $bulkCopy.DestinationTableName = "[$schemaName].[$($table.TableName)]"

    # Required in case we've added columns, they will not be in order, and as long as you specify the names here it will all work okay
    $table.Columns | %{
        $bulkCopy.ColumnMappings.Add((New-Object System.Data.SqlClient.SqlBulkCopyColumnMapping($_.ColumnName, $_.ColumnName))) | Out-Null

But as I needed to spread the load I installed SQL 2016 CTP 3.3 onto another server and copied the scripts over. They immediately started throwing a weird exception that appeared to have nothing to do with my code.

Errors             : {System.Data.SqlClient.SqlError: Expression type bit is invalid for COLLATE clause.}
ClientConnectionId : 539d4ba3-fdd1-4a82-a42d-fa874d7ae433
Class              : 16
LineNumber         : 1
Number             : 447
Procedure          :
Server             : .\SQL2016
State              : 1
Source             : .Net SqlClient Data Provider
ErrorCode          : -2146232060
Message            : Expression type bit is invalid for COLLATE clause.
Data               : {HelpLink.ProdName, HelpLink.ProdVer, HelpLink.EvtSrc, HelpLink.EvtID...}
InnerException     :
TargetSite         : Void OnError(System.Data.SqlClient.SqlException, Boolean, System.Action`1[System.Action])
StackTrace         :    at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
                        at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
                        at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler,
                     TdsParserStateObject stateObj, Boolean& dataReady)
                        at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject
                        at System.Data.SqlClient.SqlBulkCopy.RunParser(BulkCopySimpleResultSet bulkCopyHandler)
                        at System.Data.SqlClient.SqlBulkCopy.SubmitUpdateBulkCommand(String TDSCommand)
                        at System.Data.SqlClient.SqlBulkCopy.CopyBatchesAsync(BulkCopySimpleResultSet internalResults, String updateBulkCommandText, CancellationToken cts, TaskCompletionSource`1
                        at System.Data.SqlClient.SqlBulkCopy.WriteToServerInternalRestContinuedAsync(BulkCopySimpleResultSet internalResults, CancellationToken cts, TaskCompletionSource`1 source)
                        at System.Data.SqlClient.SqlBulkCopy.WriteToServerInternalRestAsync(CancellationToken cts, TaskCompletionSource`1 source)
                        at System.Data.SqlClient.SqlBulkCopy.WriteToServerInternalAsync(CancellationToken ctoken)
                        at System.Data.SqlClient.SqlBulkCopy.WriteRowSourceToServerAsync(Int32 columnCount, CancellationToken ctoken)
                        at System.Data.SqlClient.SqlBulkCopy.WriteToServer(DataTable table, DataRowState rowState)
                        at CallSite.Target(Closure , CallSite , Object , Object )
HelpLink           :
HResult            : -2146232060

Just to be sure I wasn't missing something, I traced the code and errors from the database side and it was indeed the bulk insert statement causing SQL Server to throw the error. When I ran the code on the old server, it could write to the old database server or the new database server. But when I ran the code on the new server it would fail writing to either database server!

It was a real head scratcher and I lost a good lot of time trying to work out why it was happening and which part of the stack was broken; when I remembered I never rebooted the new server after the CTP 3.3 install.

I thought there was no way this could possibly be related… and yet after I rebooted the code immediately started working and has continued working since! So let that be a reminder that sometimes you really really need to reboot after a SQL Server install otherwise it can cause weird issues.

It's possible the CTP installs a .NET update which causes this to happen. These outstanding .NET updates have been causing me a lot of grief lately but they can be picked up by checking a registry key; it's important because they can cause Data Quality Services (DQS) to fail and SQLCLR to repeatedly refuse to load. Both of those problems can be picked up in the SQL errorlog.