Deploying an RCL to Umbraco Cloud

Hey RCL’ers,

I am currently trying to deploy an Umbraco RCL (Razor Class Library) to Umbraco Cloud. I am using the v2 deployment API. I am using the official Umbraco RCL template. Its a very basic RCL that just says hello.

I am aware of workarounds to get this working such as creating the RCL as a nuget package and referencing it.

However I am trying to get Umbraco Cloud to just deploy it instead. So far its going well??, I have gotten the .NET build that Umbraco performs to pass, the v2 API returns with a success when polling the deployment status. However Kudu will error, below is the deployment log when digging into C:\home\site\deployments\{guid}

2025-08-06T16:29:12.3105749Z,Updating branch ‘master’.,43c85b5d-7a56-41d3-8e57-c702a9a880f8,0
2025-08-06T16:29:13.0762209Z,Updating submodules.,3fe52735-8bcf-4b8e-8409-d59b3a0d9e8e,0
2025-08-06T16:29:13.1230887Z,Preparing deployment for commit id ‘a01b1d7590’.,5f25c23c-e396-40cb-ab59-3d99062ceb2b,0
2025-08-06T16:29:13.2637176Z,Running custom deployment command…,88e97a7f-bc6a-4a75-9576-9ade6b654a45,0
2025-08-06T16:29:13.2949674Z,Running deployment command…,b2195157-0e60-46ad-b6bb-8986c70eacc6,0
2025-08-06T16:29:13.3574706Z,Command: C:\home\SiteExtensions\Umbraco.Cloud.Deployment.SiteExtension.Artifacts.Core\deploy.cmd,0
2025-08-06T16:29:16.6387998Z,Ensuring git configuration,0
2025-08-06T16:29:17.7013254Z,Handling ``ASP.NET`` Core Web Application deployment,0
2025-08-06T16:29:18.2950892Z,CsProjFile location C:\home\site\repository\src\UmbracoProject\UmbracoProject.csproj,0
2025-08-06T16:29:18.3419676Z,Target Major and Minor dotnet sdk version found via the csproj file ‘9.0’,0
2025-08-06T16:29:19.2013626Z,Working Sdk version ‘9.0.300’,0
2025-08-06T16:29:19.2169867Z,Wrote global.json in the repository for version ‘9.0.300’,0
2025-08-06T16:29:20.6857701Z,An issue was encountered verifying workloads. For more information, run “dotnet workload update”.,0
2025-08-06T16:29:21.8264272Z, Determining projects to restore…,0
2025-08-06T16:29:22.9358252Z, All projects are up-to-date for restore.,0
2025-08-06T16:29:47.2489060Z, MyPackage → C:\home\site\repository\MyPackage\bin\Release\net9.0\MyPackage.dll,0
2025-08-06T16:30:39.9392011Z, UmbracoProject → C:\home\site\repository\src\UmbracoProject\bin\Release\net9.0\UmbracoProject.dll,0
2025-08-06T16:30:41.2829848Z, Copying JSON schema files into project directory: appsettings-schema.Umbraco.StorageProviders.json;appsettings-schema.Umbraco.StorageProviders.AzureBlob.json;appsettings-schema.Umbraco.Forms.json;appsettings-schema.Umbraco.Deploy.json;appsettings-schema.Umbraco.Cms.json,0
2025-08-06T16:30:41.3611098Z, Copying JSON schema files into project directory: umbraco-package-schema.json,0
2025-08-06T16:30:41.3923628Z, Adding JSON schema references to appsettings-schema.json: ``https://json.schemastore.org/appsettings.json;appsettings-schema.Umbraco.StorageProviders.json#;appsettings-schema.Umbraco.StorageProviders.AzureBlob.json#;appsettings-schema.Umbraco.Forms.json#;appsettings-schema.Umbraco.Deploy.json#;appsettings-schema.Umbraco.Cms.json#,,0
2025-08-06T16:30:42.0798833Z,0
2025-08-06T16:30:42.0955044Z,Build succeeded.,0
2025-08-06T16:30:42.1111291Z, 0 Warning(s),0
2025-08-06T16:30:42.1423782Z, 0 Error(s),0
2025-08-06T16:30:42.1423782Z,0
2025-08-06T16:30:42.1580034Z,Time Elapsed 00:01:18.77,0
2025-08-06T16:32:56.3065200Z,An unknown error has occurred. Check the diagnostic log for details.,9463177c-8f0f-4cd0-8c40-d59ce5463ae4,2

Does anyone know what this error means: 2025-08-06T16:29:20.6857701Z,An issue was encountered verifying workloads. For more information, run “dotnet workload update”.,0

I cannot find a log entry for 9463177c-8f0f-4cd0-8c40-d59ce5463ae4 where should I look for this log?

Do I need to change something in the codebase to get rid of this error?

Here is some more information on how I have got the RCL to build and pass the initial first validation step. I have GitHub actions perform the NPM build tasks since Umbraco doesn’t have newer version of Node (NPM) available. This gets added to the artifact.

I then add " Condition=“‘$(UMBRACO__CLOUD__ISRUNNINGONCLOUD)’ != ‘true’ AND ‘$(ENVIRONMENT__PROJECTID)’ == ‘’” to prevent Umbraco Cloud running the NPM tasks so it just focuses on the .NET build part and it passes.

Again to summarise, Does anyone know what this error means: 2025-08-06T16:29:20.6857701Z,An issue was encountered verifying workloads. For more information, run “dotnet workload update”.,0. Is it significant or something to ignore?

I cannot find a log entry for 9463177c-8f0f-4cd0-8c40-d59ce5463ae4 where should I look for this log? I don’t see anything in: C:\home\LogFiles\kudu>

Hi Matthew,

Are you pushing your RCL csproj and source code to Cloud ?

I know RCL’s work on Cloud if they are registered as nuget package.

Dave

We’re doing exactly this! I believe that error comes from Cloud trying to run NPM, which is NPM version 4 or something silly on the Cloud servers. Cloud can’t run your NPM build for you, so that condition is needed.

There will be a DevRel Deep Dives video on this next week which is part 2 of this one, but in the mean time, feel free to peruse our repository in the mean time.

Specifically, I found this to work in the csproj file, think it looks a little different from yours:

  <Target Name="BuildClient" 
          BeforeTargets="AssignTargetPaths" 
          DependsOnTargets="RestoreClient" 
          Inputs="@(ClientAssetsInputs)" 
          Outputs="$(IntermediateOutputPath)client.complete.txt"
          Condition="!('$(UMBRACO__CLOUD__ISRUNNINGONCLOUD)' == 'true' OR '$(ENVIRONMENT__PROJECTID)' != '')">
    <Message Importance="high" Text="Executing Client NPM build script..." />
    <Exec Command="npm run build" WorkingDirectory="Client" />
    <ItemGroup>
      <_ClientAssetsBuildOutput Include="wwwroot\App_Plugins\**" />
    </ItemGroup>
    <WriteLinesToFile File="$(IntermediateOutputPath)client.complete.txt" Lines="@(_ClientAssetsBuildOutput)" Overwrite="true" />
  </Target>

We run NPM in the GitHub workflow so it has the assets in the Client folder that will then be compiled into the RCL (see: open-source-umbraco-cloud/.github/workflows/cloud-artifact.yml at develop · LottePitcher/open-source-umbraco-cloud · GitHub)

Hope that helps!

Hmm, come to think of it, that indicates that your .NET SDK version might not be what is expected? Is your Cloud site configured to use .NET 8 or 9 and is your project configured to use the same version?

Its using .NET 9, its a newly minted Umbraco 16 site for testing.

Here are the CSPROJ’s

RCL

<Project Sdk="Microsoft.NET.Sdk.Razor">
  <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <StaticWebAssetBasePath>/</StaticWebAssetBasePath>
  </PropertyGroup>
  <PropertyGroup>
    <PackageId>MyPackage</PackageId>
    <Product>MyPackage</Product>
    <Title>MyPackage</Title>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Umbraco.Cms.Web.Website" Version="16.0.0" />
    <PackageReference Include="Umbraco.Cms.Web.Common" Version="16.0.0" />
    <PackageReference Include="Umbraco.Cms.Api.Common" Version="16.0.0" />
    <PackageReference Include="Umbraco.Cms.Api.Management" Version="16.0.0" />
  </ItemGroup>
  <ItemGroup>
    <ClientAssetsInputs Include="Client\**" Exclude="$(DefaultItemExcludes)" />
    <!-- Dont include the client folder as part of packaging nuget build -->
    <Content Remove="Client\**" />
    <!-- However make the Umbraco-package.json included for dotnet pack or nuget package and visible to the solution -->
    <None Include="Client\public\umbraco-package.json" Pack="false" />
  </ItemGroup>
  <ItemGroup>
    <Folder Include="wwwroot\" />
  </ItemGroup>
  <!-- Restore and build Client files -->
  <Target Name="RestoreClient" Inputs="Client\package.json;Client\package-lock.json" Outputs="Client\node_modules\.package-lock.json"  Condition="'$(UMBRACO__CLOUD__ISRUNNINGONCLOUD)' != 'true' AND '$(ENVIRONMENT__PROJECTID)' == ''">
    <Message Importance="high" Text="Restoring Client NPM packages..." />
    <Exec Command="npm i" WorkingDirectory="Client" />
  </Target>
  <Target Name="BuildClient" BeforeTargets="AssignTargetPaths" DependsOnTargets="RestoreClient" Inputs="@(ClientAssetsInputs)" Outputs="$(IntermediateOutputPath)client.complete.txt"  Condition="'$(UMBRACO__CLOUD__ISRUNNINGONCLOUD)' != 'true' AND '$(ENVIRONMENT__PROJECTID)' == ''">
    <Message Importance="high" Text="Executing Client NPM build script..." />
    <Exec Command="npm run build" WorkingDirectory="Client" />
    <ItemGroup>
      <_ClientAssetsBuildOutput Include="wwwroot\App_Plugins\**" />
    </ItemGroup>
    <WriteLinesToFile File="$(IntermediateOutputPath)client.complete.txt" Lines="@(_ClientAssetsBuildOutput)" Overwrite="true" />
  </Target>

</Project>

Website

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <CompressionEnabled>false</CompressionEnabled> <!-- Disable compression. E.g. for umbraco backoffice files. These files should be precompressed by node and not let dotnet handle it -->
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Umbraco.Cloud.Cms" Version="16.0.0" />
    <PackageReference Include="Umbraco.Cloud.StorageProviders.AzureBlob" Version="16.0.0" />
    <PackageReference Include="Umbraco.Cms" Version="16.0.0" />
    <PackageReference Include="Umbraco.Deploy.Cloud" Version="16.0.0" />
    <PackageReference Include="Umbraco.Forms" Version="16.0.0" />
    <PackageReference Include="Umbraco.Forms.Deploy" Version="16.0.0" />
  </ItemGroup>
  <ItemGroup>
    <!-- Opt-in to app-local ICU to ensure consistent globalization APIs across different platforms -->
    <PackageReference Include="Microsoft.ICU.ICU4C.Runtime" Version="72.1.0.3" />
    <ProjectReference Include="..\..\MyPackage\MyPackage.csproj" />
    <RuntimeHostConfigurationOption Include="System.Globalization.AppLocalIcu" Value="72.1.0.3" Condition="$(RuntimeIdentifier.StartsWith('linux')) or $(RuntimeIdentifier.StartsWith('win')) or ('$(RuntimeIdentifier)' == '' and !$([MSBuild]::IsOSPlatform('osx')))" />
  </ItemGroup>
  <PropertyGroup>
    <!-- Razor files are needed for the backoffice to work correctly -->
    <CopyRazorGenerateFilesToPublishDirectory>true</CopyRazorGenerateFilesToPublishDirectory>
  </PropertyGroup>
  <PropertyGroup>
    <!-- Remove RazorCompileOnBuild and RazorCompileOnPublish when not using ModelsMode InMemoryAuto -->
    <RazorCompileOnBuild>false</RazorCompileOnBuild>
    <RazorCompileOnPublish>false</RazorCompileOnPublish>
  </PropertyGroup>
</Project>

Just to reiterate the build passes in Github and Umbraco Cloud. However from what I can see Umbraco Cloud performs two builds. The first one I suspect is some validation the v2 API returns a status based on this first pass. I get a successful response as NPM is not being ran. Then a second deployment is performed this time with KUDU and it fails here and I cannot work out where to find the error. I feel like the workload error is a red herring. Its an error within KUDU so its probably buried somewhere on in the web app file system.

Ah interesting, it doesn’t fail silently, it fails with a red error in the Cloud portal too?

I am having trouble uploading the screenshot here. I see the same error as what I have shown. I’ll DM it to you on discord

Potentially its still trying to run NPM in the second pass?

I just learnt that you can run dir env: inside of KUDU to see all the environment variables. Going to try updating the condition to look for ‘$(ScmType)’ != ‘LocalGit’”:

Condition=“‘$(UMBRACO__CLOUD__ISRUNNINGONCLOUD)’ != ‘true’
AND ‘$(ENVIRONMENT__PROJECTID)’ == ‘’
AND ‘$(ScmType)’ != ‘LocalGit’”

I didn’t see UMBRACO__CLOUD__ISRUNNINGONCLOUD or ENVIRONMENT__PROJECTID in the output.

Right so that worked!

Updating the condition to be

Condition="'$(UMBRACO__CLOUD__ISRUNNINGONCLOUD)' != 'true' AND '$(ENVIRONMENT__PROJECTID)' == '' AND '$(ScmType)' != 'LocalGit'"

Allows KUDU to process the RCL, I can see my RCL in the dashboard now.

Glad that worked! Did you try my Condition instead?

Condition="!('$(UMBRACO__CLOUD__ISRUNNINGONCLOUD)' == 'true' OR '$(ENVIRONMENT__PROJECTID)' != '')"

I think those two checks should be enough, I actually hope it’s possible to remove the ENVIRONMENT__PROJECTID as well, that would simplify things. But I haven’t tried yet.

Note the ! “NOT” operator that I don’t see in yours. I think that’s the key! I bet only doing this would work too:

Condition="!('$(UMBRACO__CLOUD__ISRUNNINGONCLOUD)' == 'true'"

I don’t see any of those variables pop up when searching in KUDU environment variables:

ENVIRONMENT__PROJECTID

It looks like two build processes are going on the first one will have UMBRACO__CLOUD__ISRUNNINGONCLOUD

But the second is done in KUDU and those values aren’t there so I just picked one that seemed unique enough to KUDU and it allowed KuduSync to run.

Yeah the kudu environment is different from where the actual dotnet build happens on Cloud I believe! So that would explain it.

But I see, that might be why I also needed the other check.