U4-8798 - Compositions break document types when replacing existing property with same alias

Created by Bjarne Fyrstenborg 01 Aug 2016, 17:21:11 Updated by Sebastiaan Janssen 22 Aug 2016, 09:33:53

Tags: Backport Unscheduled

Is duplicated by: U4-8880

Relates to: U4-8663

I am having some issues, where the compositions are breaking the document types, when I have a deep folder structure in document types. Tested with Umbraco 7.5.0-beta2

I have the following folder structure: Document Types > Compositions > Nested Content Inside "Nested Content" folder I have two document types: "customInputBase" (same alias) and "customInputCheckbox". It is meant for adding a few simple custom form fields to a form, where "customInputBase" has base properties like a form label (textbox), that the other document types can use too.

First I created these two document types, then adding a property Label (alias: cfLabel, datatype: textbox) to both document types. No issues.

Then I removed "cfLabel" property from "customInputCheckbox" (without save) and adding composition property "cfLabel" from "customInputBase".

After save is get ysod as a screenshot and when refreshing the view, it returns "500 internal server error":

)]}',
{"Message":"An error has occurred.","ExceptionMessage":"ContentType with alias 'customInputBase' was added as a Composition to ContentType with alias 'customInputCheckbox', but there was a conflict on the following PropertyTypes: 'cfLabel'. PropertyTypes must have a unique alias across all Compositions in order to compose a valid ContentType Composition.","ExceptionType":"Umbraco.Core.Exceptions.InvalidCompositionException","StackTrace":"   at Umbraco.Core.Models.ContentTypeCompositionBase.AddContentType(IContentTypeComposition contentType)\r\n   at Umbraco.Core.Persistence.Repositories.ContentTypeBaseRepository`1.ContentTypeQueryMapper.MapContentTypeChildren[TRepo](IContentTypeComposition[] contentTypes, Database db, ISqlSyntaxProvider sqlSyntax, TRepo contentTypeRepository, IDictionary`2 allParentContentTypeIds)\r\n   at Umbraco.Core.Persistence.Repositories.ContentTypeBaseRepository`1.ContentTypeQueryMapper.GetContentTypes[TRepo](Database db, ISqlSyntaxProvider sqlSyntax, TRepo contentTypeRepository, ITemplateRepository templateRepository)\r\n   at Umbraco.Core.Persistence.Repositories.ContentTypeRepository.PerformGetAll(Int32[] ids)\r\n   at Umbraco.Core.Cache.FullDataSetRepositoryCachePolicy`2.PerformGetAll(Func`2 getFromRepo)\r\n   at Umbraco.Core.Cache.FullDataSetRepositoryCachePolicy`2.GetAll(TId[] ids, Func`2 getFromRepo)\r\n   at Umbraco.Core.Persistence.Repositories.RepositoryBase`2.GetAll(TId[] ids)\r\n   at Umbraco.Core.Persistence.Repositories.ContentTypeRepository.PerformGetAll(Guid[] ids)\r\n   at Umbraco.Core.Persistence.Repositories.ContentTypeRepository.<get_CachePolicyFactory>b__0()\r\n   at Umbraco.Core.Cache.FullDataSetRepositoryCachePolicy`2.<Get>b__6(TId[] ids)\r\n   at Umbraco.Core.Cache.FullDataSetRepositoryCachePolicy`2.PerformGetAll(Func`2 getFromRepo)\r\n   at Umbraco.Core.Cache.FullDataSetRepositoryCachePolicy`2.GetAll(TId[] ids, Func`2 getFromRepo)\r\n   at Umbraco.Core.Cache.FullDataSetRepositoryCachePolicy`2.Get(TId id, Func`2 getFromRepo)\r\n   at Umbraco.Core.Persistence.Repositories.RepositoryBase`2.Get(TId id)\r\n   at Umbraco.Core.Services.ContentTypeService.GetContentType(Int32 id)\r\n   at Umbraco.Web.Editors.ContentTypeController.GetById(Int32 id)\r\n   at lambda_method(Closure , Object , Object[] )\r\n   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters)\r\n   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments)\r\n   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"}

It seems to be a similar issue as this one https://our.umbraco.org/forum/extending-umbraco-and-using-the-api/79011-ysod-when-adding-composition-doc-type I experienced today and it breaks the backoffice UI - not only the document types are inaccessible, also the content types.

NOTE: It seems only to be an issue when the properties (on two different document types) has same alias, and when you remember to save document type after the property "cfLabel" was removed from "customInputCheckbox" BEFORE using the composition property "cfLabel" from "customInputBase" (so "cfLabel" has been removed from "customInputCheckbox" before adding from "customInputBase") - if you just remove the property and select the composition doc type property and hit save I get this issue, which seems to break stuff.

I am able to reproduce it in both Umbraco 7.4.3 and 7.5.0-beta2

Here is a screen capture of how to test it https://bjarnefyrstenborg.tinytake.com/sf/ODc3NDAxXzM3Njk4NzU Notice that first, when I removed the property "cfLabel" + save.. then the composition property is disabled - but it is not disabled when with removing it without save, which allow me to pick the composition "cfLabel" property, when it actually already has a property "cfLabel" (because it has not been saved yet) - and it seems to be this scenario where it cause these ysod's.

8 Attachments

Comments

Bjarne Fyrstenborg 01 Aug 2016, 18:51:17

After this issue breaking the backoffice UI, I had a look at the SQL CE database (but I also have the issue for MSSQL databases).

In the table cmsPropertyType it had now two rows with Alias "cfLabel".

I deleted the last row of "cfLabel" in this table and now I can at least access the document types and content nodes again. Hopefully it doesn't break anything else?

--SELECT * FROM cmsPropertyType
--WHERE Alias = 'cfLabel'
--AND id = 62

DELETE FROM cmsPropertyType
WHERE Alias = 'cfLabel'
AND id = 62


Dan Patching 02 Aug 2016, 16:39:25

I've reproduced this problem in 7.4.3 ;)


Ali Sheikh Taheri 04 Aug 2016, 11:09:13

I did have the the same problem and managed to fix it by deleting the 'title' and 'bodyText' from cmsPropertyType ''' ContentType with alias 'Content' was added as a Composition to ContentType with alias 'Error404', but there was a conflict on the following PropertyTypes: 'title, bodyText'. PropertyTypes must have a unique alias across all Compositions in order to compose a valid ContentType Composition. '''

If the alias has to be unique across all the composition why the system allow users to create it rather than giving an error message?


Sebastiaan Janssen 04 Aug 2016, 12:09:53

The fix for this issue was implemented in U4-8663 (after beta2 was released). I'll mark this as fixed now.


Priority: Major

Type: Bug

State: Fixed

Assignee:

Difficulty: Normal

Category:

Backwards Compatible: True

Fix Submitted:

Affected versions: 7.5.0, 7.4.3

Due in version: 7.5.0

Sprint: Sprint 39

Story Points:

Cycle: