question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Upgrade from v7 to v8.6+ throws exception on media URL migration

See original GitHub issue

Overview

In trying to upgrade a database that uses RTEs and Grid heavily, the upgrade fails if I got directly to v8.6.0. It works if I first go to an earlier version, and then try to go to v8.6.0. The error is in the ConvertTinyMceAndGridMediaUrlsToLocalLink migration, on line 113.

Details

Umbraco version

I am seeing this issue on Umbraco version: v8.6.0, from v7.15.3

Bug summary

This is caused by the ConvertTinyMceAndGridMediaUrlsToLocalLink migration using a service reference to retrieve data instead of using direct database access. Thus when new columns were introduced in the AddPropertyTypeValidationMessageColumns migration, the service is trying to read from these new columns that don’t yet exist in the database.

Steps to reproduce

Create a v7.15.3 database, and add Grid and RTE data that contain media links. Then try to upgrade the database to v8.6.0.

Expected result

The site is upgraded to v8.6.0 successfully.

Actual result

The upgrade wizard fails with the message “The database failed to upgrade. ERROR: The database configuration failed with the following message: Invalid column name ‘mandatoryMessage’. Invalid column name ‘validationRegExpMessage’. Please check log file for additional information (can be found in ‘/App_Data/Logs/’)”. Reviewing the trace log shows the following stack trace for that error:

System.Data.SqlClient.SqlException (0x80131904): Invalid column name 'mandatoryMessage'.
Invalid column name 'validationRegExpMessage'.
   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.SqlDataReader.TryConsumeMetaData()
   at System.Data.SqlClient.SqlDataReader.get_MetaData()
   at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted)
   at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
   at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
   at StackExchange.Profiling.Data.ProfiledDbCommand.ExecuteDbDataReader(CommandBehavior behavior) in C:\projects\dotnet\src\MiniProfiler.Shared\Data\ProfiledDbCommand.cs:line 223
   at Umbraco.Core.Persistence.FaultHandling.RetryPolicy.ExecuteAction[TResult](Func`1 func) in C:\projects\umbraco-cms\src\Umbraco.Core\Persistence\FaultHandling\RetryPolicy.cs:line 172
   at NPoco.Database.ExecuteReaderHelper(DbCommand cmd)
   at NPoco.Database.ExecuteDataReader(DbCommand cmd)
   at NPoco.Database.<QueryImp>d__164`1.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at Umbraco.Core.Persistence.Repositories.Implement.ContentTypeCommonRepository.MapGroupsAndProperties(IDictionary`2 contentTypes) in C:\projects\umbraco-cms\src\Umbraco.Core\Persistence\Repositories\Implement\ContentTypeCommonRepository.cs:line 192
   at Umbraco.Core.Persistence.Repositories.Implement.ContentTypeCommonRepository.GetAllTypesInternal() in C:\projects\umbraco-cms\src\Umbraco.Core\Persistence\Repositories\Implement\ContentTypeCommonRepository.cs:line 114
   at Umbraco.Core.Cache.AppCacheExtensions.<>c__DisplayClass0_0`1.<GetCacheItem>b__0() in C:\projects\umbraco-cms\src\Umbraco.Core\Cache\AppCacheExtensions.cs:line 22
   at Umbraco.Core.Cache.FastDictionaryAppCacheBase.<>c__DisplayClass21_0.<GetSafeLazy>b__0() in C:\projects\umbraco-cms\src\Umbraco.Core\Cache\FastDictionaryAppCacheBase.cs:line 285
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Umbraco.Core.Cache.WebCachingAppCache.GetInternal(String key, Func`1 factory, Nullable`1 timeout, Boolean isSliding, CacheItemPriority priority, CacheItemRemovedCallback removedCallback, String[] dependentFiles) in C:\projects\umbraco-cms\src\Umbraco.Core\Cache\WebCachingAppCache.cs:line 174
   at Umbraco.Core.Cache.WebCachingAppCache.Get(String key, Func`1 factory, Nullable`1 timeout, Boolean isSliding, CacheItemPriority priority, CacheItemRemovedCallback removedCallback, String[] dependentFiles) in C:\projects\umbraco-cms\src\Umbraco.Core\Cache\WebCachingAppCache.cs:line 40
   at Umbraco.Core.Cache.DeepCloneAppCache.Get(String key, Func`1 factory, Nullable`1 timeout, Boolean isSliding, CacheItemPriority priority, CacheItemRemovedCallback removedCallback, String[] dependentFiles)
   at Umbraco.Core.Persistence.Repositories.Implement.ContentTypeCommonRepository.GetAllTypes() in C:\projects\umbraco-cms\src\Umbraco.Core\Persistence\Repositories\Implement\ContentTypeCommonRepository.cs:line 48
   at Umbraco.Core.Persistence.Repositories.Implement.MediaTypeRepository.PerformGetAll(Int32[] ids) in C:\projects\umbraco-cms\src\Umbraco.Core\Persistence\Repositories\Implement\MediaTypeRepository.cs:line 54
   at Umbraco.Core.Cache.FullDataSetRepositoryCachePolicy`2.GetAllCached(Func`2 performGetAll) in C:\projects\umbraco-cms\src\Umbraco.Core\Cache\FullDataSetRepositoryCachePolicy.cs:line 166
   at Umbraco.Core.Cache.FullDataSetRepositoryCachePolicy`2.Get(TId id, Func`2 performGet, Func`2 performGetAll)
   at Umbraco.Core.Persistence.Repositories.Implement.MediaRepository.MapDtoToContent(ContentDto dto) in C:\projects\umbraco-cms\src\Umbraco.Core\Persistence\Repositories\Implement\MediaRepository.cs:line 538
   at Umbraco.Core.Services.Implement.MediaService.GetMediaByPath(String mediaPath) in C:\projects\umbraco-cms\src\Umbraco.Core\Services\Implement\MediaService.cs:line 631
   at Umbraco.Core.Migrations.Upgrade.V_8_1_0.ConvertTinyMceAndGridMediaUrlsToLocalLink.<>c__DisplayClass3_0.<UpdateMediaUrls>b__0(Match match) in C:\projects\umbraco-cms\src\Umbraco.Core\Migrations\Upgrade\V_8_1_0\ConvertTinyMceAndGridMediaUrlsToLocalLink.cs:line 113
   at System.Text.RegularExpressions.RegexReplacement.Replace(MatchEvaluator evaluator, Regex regex, String input, Int32 count, Int32 startat)
   at System.Text.RegularExpressions.Regex.Replace(String input, MatchEvaluator evaluator)
   at Umbraco.Core.Migrations.Upgrade.V_8_1_0.ConvertTinyMceAndGridMediaUrlsToLocalLink.UpdateMediaUrls(Regex mediaLinkPattern, String value, Boolean& changed) in C:\projects\umbraco-cms\src\Umbraco.Core\Migrations\Upgrade\V_8_1_0\ConvertTinyMceAndGridMediaUrlsToLocalLink.cs:line 103
   at Umbraco.Core.Migrations.Upgrade.V_8_1_0.ConvertTinyMceAndGridMediaUrlsToLocalLink.Migrate() in C:\projects\umbraco-cms\src\Umbraco.Core\Migrations\Upgrade\V_8_1_0\ConvertTinyMceAndGridMediaUrlsToLocalLink.cs:line 59
   at Umbraco.Core.Migrations.MigrationBase.Umbraco.Core.Migrations.IMigration.Migrate() in C:\projects\umbraco-cms\src\Umbraco.Core\Migrations\MigrationBase.cs:line 73
   at Umbraco.Core.Migrations.MigrationPlan.Execute(IScope scope, String fromState, IMigrationBuilder migrationBuilder, ILogger logger) in C:\projects\umbraco-cms\src\Umbraco.Core\Migrations\MigrationPlan.cs:line 316
   at Umbraco.Core.Migrations.Upgrade.Upgrader.Execute(IScopeProvider scopeProvider, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, ILogger logger) in C:\projects\umbraco-cms\src\Umbraco.Core\Migrations\Upgrade\Upgrader.cs:line 67
   at Umbraco.Core.Migrations.Install.DatabaseBuilder.UpgradeSchemaAndData(MigrationPlan plan) in C:\projects\umbraco-cms\src\Umbraco.Core\Migrations\Install\DatabaseBuilder.cs:line 501

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:1
  • Comments:38 (25 by maintainers)

github_iconTop GitHub Comments

3reactions
benjaminccommented, Jan 6, 2021

Its pretty disrespectful to throw shade on the publicly available package I created to fix the problem I identified for you when your internal testing failed, and then submitted a tested fix for which you ignored, and so finally created a community package to fix the issue instead of just fixing it for myself, all because my one-off package to fix your hole doesn’t have as much documentation as you’d like to see. That’s pretty low.

And as has been said above, this isn’t affecting just a few people. This bug actually affect EVERY upgrade that tries to go directly from v7 to v8.6 or above. So either you were an early adopter, or you hit this bug. There isn’t any way around it, and it doesn’t only affect you if you have a specific set of data. It affects every upgrade. If you haven’t had more reports of it, that means one of two things: either your clients aren’t upgrading to v8 or they are so used to poor service that they aren’t even bothering to mention it to you anymore. Both of those should really be pretty chilling options to anyone who cares about their product.

2reactions
benjaminccommented, Feb 12, 2021

The problem comes because a migration (designed to interact directly with the database while the database is in a state of flux) is calling into the service layer (designed to interact with a stable database to apply current business logic). If you look at what it is trying to get from the service layer, it is just trying to get a single piece of information about media items. This could very easily be achieved with a simple DTO query, my guess is that the migration developer was simply more familiar with how to get it via the service layer, and so went with what they were familiar with. Without any standards on what should or shouldn’t be done in migrations, this approach completely makes sense.

I think the long term fix for this is that migrations included as part of the core should simply not be allowed to use the service layer. Any data access should be done with queries and version-specific DTOs, similar to what was done for the bulk of the 8.0 and 8.1 migrations. It was done right for the bulk of the 8.X upgrade migrations, I think this one just slipped through because there wasn’t a standard that a reviewer could check against, because the problem wasn’t well understood. Now that the impact of this is seen, just add a note for reviewers to check for and not allow service layer access in migrations, and rewrite this one existing migration to not use the service layer, but to do a direct DB query. Problem solved.

Read more comments on GitHub >

github_iconTop Results From Across the Web

upgrade is ridiculously complicated - Using Umbraco And ...
I have now spent five days of my holiday trying to upgrade one web from Umbraco 7.10.4 to 8.10.1. I give up. It...
Read more >
How to Upgrade Umbraco Version 7 to Version 8 - ProWorks
Step 5: Run v7 migration to convert link pickers to the Umbraco.MultiUrlPicker. In all of our Umbraco 7 sites, we installed and made...
Read more >
Untitled
... spell it Upgrade from v7 to v8.6+ throws exception on media URL Why You ... WebJun 15, 2019 · Migrating from Umbraco...
Read more >
Brightcove Player 7 Migration Guide
Brightcove Player 7 Migration Guide. In this topic, you will learn about the new improvements and features with the major version release for...
Read more >
Breaking changes in 7.0 | Elasticsearch Guide [7.17]
The Migration Assistance API has been functionally replaced by the Deprecation Info API, and the Migration Upgrade API is not used for the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found