Bug Report — Epidemic Sound DaVinci Resolve Plugin

Studio feature hangs forever on Resolve 21 beta because plugin‑initiated renders are routed to BgRenderManager

Reported by Captain · geekception@gmail.com · April 2026

TL;DR

On DaVinci Resolve 21.0.0 build 0020 (public beta), the plugin's Studio feature gets permanently stuck after the timeline render finishes. The render completes successfully on disk, but the plugin never reimports the clip and never starts the AI music match — the spinner just spins forever.

Root cause: Resolve 21 routes plugin-initiated StartRendering jobs through the background render queue (BgRenderManager), but the plugin only listens for the foreground "RenderStop" callback. The callback never fires, so the plugin's Promise never resolves.

Workaround that fixes it 100%: Disable background rendering in Resolve's project settings (Project Settings → General Options → uncheck background rendering). Studio works perfectly after that, and renders are actually faster too.

Environment

DaVinci Resolve
21.0.0 build 0020 (public beta)
Plugin version
v1.19.5
Plugin manifest Id
com.blackmagicdesign.resolve.es
Interface version
2
Operating system
macOS 26.4 (Tahoe)
Hardware
Mac Studio M3 Ultra

Reproduction steps

  1. Open any timeline in Resolve 21 with default project settings (background rendering enabled).
  2. Set in/out points on the timeline.
  3. Open the Epidemic Sound plugin → click Studio to find AI-matched music.
  4. The plugin renders the in/out range to ~/Library/Application Support/Epidemic Sound/es_davinci_resolve/__capture__video_<uuid>.mov.
  5. Render completes on disk. Resolve's debug log confirms BgRenderManager: Background render job finished (status:1).
  6. Plugin UI never advances. The clip is never reimported, no API call to your music-match endpoint is ever made.

Root cause

The relevant function is cY (the encodeVideoSequence IPC handler) in davinci/src/main.js. Decompiled from the minified bundle, the structure is:

async function encodeVideoSequence(...) {
  const project = projectManager.GetCurrentProject();
  // ... build render settings (H264, MarkIn/MarkOut, TargetDir, CustomName) ...
  project.SetRenderSettings(K);
  const jobId = project.AddRenderJob();

  const result = await new Promise(resolve => {
    const onStop = () => {
      resolveApi.DeregisterCallback("RenderStop");
      if (project.GetRenderJobStatus(jobId).JobStatus !== "Complete") {
        resolve({ errorCode: "EncodingError" });
        return;
      }
      resolve({ outputFilePath, encodedStartTime, encodedEndTime, uuid: jobId });
    };
    resolveApi.RegisterCallback("RenderStop", onStop);
    project.StartRendering([jobId]);   // <-- in Resolve 21 beta, this goes to BgRenderManager
  });
  // ... upload to ES API, return clip metadata ...
}

The Promise depends entirely on "RenderStop" firing. In Resolve 21.0.0 build 0020, plugin-initiated StartRendering calls are dispatched to BgRenderManager instead of the foreground render queue, and BgRenderManager does not fire the "RenderStop" callback. The Promise hangs forever; the upload code downstream of the await never runs.

Evidence

Confirmed in three independent ways. All raw files are downloadable below.

1. Resolve debug log shows the render completing on the background queue

15:46:53  UiWIPlugin                  : Loaded plugin: com.blackmagicdesign.resolve.es
15:46:53  UiWIPluginMessageProcessor  : Using interface version: 2
15:47:24  BgRenderManager             : Background render job finished (status:1) id a313a235-...
15:48:19  UiWIPlugin                  : Unloaded plugin: com.blackmagicdesign.resolve.es
15:48:46  UiWIPlugin                  : Loaded plugin: (reload)
15:49:09  BgRenderManager             : Background render job finished (status:1) id e6800248-...

The job is dispatched to BgRenderManager, not the foreground render manager. There is no "RenderStop" event in the log.

2. Render-job XML shows the render itself is healthy

The batch-render XML at Resolve Projects/.../Batch Renders/<jobId>.xml shows:

<Status>COMPLETE</Status>
<CompletionPercentage>100</CompletionPercentage>
<RecordTargetDir>/Users/.../Library/Application Support/Epidemic Sound/es_davinci_resolve</RecordTargetDir>
<RecordPrefix>__capture__video_53e82a36-893f-4745-9955-70c76850ea36.mov</RecordPrefix>

The file exists on disk at the expected path. The render is fine. The problem is purely on the callback side.

3. Plugin Sentry scope confirms the Hub side is healthy

The plugin's Sentry scope file (~/Library/Application Support/es-plugin-installer/sentry/scope_v3.json) shows all pgw.epidemicsound.com /api/version/ calls returning 200 OK and errors: 0, status: ok. The Hub side of the plugin is healthy. No upload to the music-match endpoint is ever attempted, because the Promise that gates it never resolves.

4. Workaround verified

After disabling background rendering in Resolve's project settings, Studio works on the first try, renders are noticeably faster, and the clip reimports + music match runs as expected.

Download raw evidence

⬇ Download all evidence (zip)
ResolveDebug.txt (excerpt)
Plugin load → render → orphan timeline from ~/Library/Application Support/Blackmagic Design/DaVinci Resolve/logs/
Download
e6800248-dca4-4fb0-aa6c-ff9ccf721ba3.xml
Completed batch-render job XML showing <Status>COMPLETE</Status>
Download
scope_v3.json
Plugin Sentry scope showing all Hub-side API calls returning 200 OK
Download
manifest.xml
Plugin manifest confirming v1.19.5 / interface version 2
Download
cY-decompiled.js
Decompiled encodeVideoSequence function from main.js for engineering reference
Download

Suggested fix

Two layered fixes that would close this hole and make the plugin more robust against future Resolve queue routing changes:

  1. Register both completion callbacks. Listen for "RenderStop" and the equivalent background-queue completion event (or poll GetRenderJobStatus(jobId) until status is Complete / Failed as a fallback). Resolve whichever fires first.
  2. Add a polling fallback / timeout. Even if the callback registration is correct, a setInterval checking project.GetRenderJobStatus(jobId).JobStatus every ~500ms with a sensible timeout would prevent any future Promise-stuck regression and let you surface a real error to the user instead of an infinite spinner.

A defensive Promise.race([callbackPromise, pollPromise]) pattern would have caught this entirely.

Why I'm sending this

I lost a couple of hours debugging this because the plugin gives no UI signal that it's stuck — it just looks like it's still working. I've already worked around it on my end (disable background rendering), and Studio is back to being the killer feature it always has been. I just don't want anyone else who upgrades to Resolve 21 to hit the same wall, and I figure your engineers will appreciate a fully-diagnosed bug report rather than a vague "Studio doesn't work" ticket.

Happy to test a fix if anyone from the plugin team wants to ship me a build.