Over the past few weeks, several Optimizely CMS projects began experiencing a puzzling failure: XHtmlString fields stopped initializing TinyMCE in the edit interface. The editor simply refused to load, leaving users unable to manage rich text content.
This issue surfaced in multiple unrelated projects, so it was clear the root cause wasn’t project-specific code. After some investigation, we traced the failure to something unexpected: the .NET SDK version used by the Azure DevOps build pipeline.
The Symptom
Projects deployed to Optimizely DXP began showing:
- TinyMCE not initializing for XHtmlString fields
- The editor window appearing as plain text
- No console error tied directly to TinyMCE
- A dependency resolution warning pointing to the generated
.deps.jsonfile
Locally everything worked flawlessly, which made the issue even more confusing.
The Root Cause: Azure DevOps Was Building with .NET 10
The real issue turned out to be that the Azure DevOps pipeline was using .NET SDK 10.0.100, a preview/next-gen SDK that is not compatible with Optimizely CMS 12.
This resulted in a different .deps.json file being generated during dotnet publish. That file included unexpected reference assemblies and compileOnly entries that prevented the Optimizely UI framework — including TinyMCE — from loading correctly in DXP.
Optimizely CMS 12 is designed and tested for .NET 6 and .NET 8, not .NET 10.
How to Confirm Your Pipeline Is Using the Wrong SDK
Add this step temporarily in your Azure DevOps pipeline:
- script: dotnet --info
displayName: "Show .NET SDK info"
When the pipeline runs, check the output.
If you see something like:
.NET SDK:
Version: 10.0.100
then your pipeline is using the wrong SDK — and that is the root of the TinyMCE failure.
The Fix: Pin the Pipeline to .NET 8
To ensure consistency with local builds and compatibility with DXP, add the following step before restore/build in your pipeline:
- task: UseDotNet@2
displayName: "Use .NET 8 SDK"
inputs:
packageType: 'sdk'
version: '8.0.x'
This forces the pipeline to install and use the correct .NET 8 SDK, ensuring that:
- The same dependency graph is produced locally and in DevOps
.deps.jsonis generated correctly- TinyMCE initializes normally in the Optimizely edit interface
After applying this fix, projects deployed successfully and TinyMCE loaded without issues.
Why This Happens
The hosted agent windows-latest recently began shipping with .NET 10 preview SDKs preinstalled.
If your pipeline does not explicitly specify a .NET version, Azure DevOps defaults to the newest available SDK, even if your project was built for .NET 8.
This means the SDK influences:
- Dependency resolution
- Runtime asset inclusion
.deps.jsongeneration
Tiny differences here can break runtime frameworks like the Optimizely UI.
Recommended Best Practices
To prevent similar issues in the future:
✔ Always pin your SDK in the pipeline
Use UseDotNet@2 explicitly.
✔ Add a global.json in your project root
Example:
{
"sdk": {
"version": "8.0.403",
"rollForward": "disable"
}
}
This ensures both local and CI environments use the same SDK.
✔ Periodically check your build logs
Using dotnet --info during troubleshooting helps detect unintended version changes early.
Conclusion
This TinyMCE initialization issue turned out to be a great example of how build environments silently affect runtime behavior. Even when the application compiles and publishes successfully, an unexpected SDK version can introduce subtle changes that break functionality in production.
By explicitly pinning your .NET SDK to version 8 in Azure DevOps (and ideally through a global.json file), you ensure consistent behavior across environments and avoid issues like this one.
If you encounter similar UI issues in Optimizely, checking the SDK version in your pipeline should be one of the first steps.