azureazure-devopstfs

VSS.SDK.min.js:2 No handler found on any channel for message


I am trying to create an Azure DevOps extension (in my case for Server 2020, on-premises, xml process) and for my configuration hub I keep running into "VSS.SDK.min.js:2 No handler found on any channel for message:" console errors.

I think the problem is somehow connected to the import of the sdk and/or api:

import { WorkItemFormService } from "TFS/WorkItemTracking/Services";
import * as RestClient from "TFS/WorkItemTracking/RestClient";
import { WorkItemTrackingHttpClient } from "TFS/WorkItemTracking/RestClient";
import * as ExtensionContracts from "TFS/WorkItemTracking/ExtensionContracts";
import * as SDK from "azure-devops-extension-sdk";
import { CommonServiceIds, IExtensionDataService, IExtensionDataManager } from "azure-devops-extension-api";

I then read the configuration information using

let provider = () => {
  return {
    onLoaded: async (workItemLoadedArgs: ExtensionContracts.IWorkItemLoadedArgs) => {
      controller = new Controller(workItemLoadedArgs.id);

      // ——— Debug: load and log the ConfigHub doc ———
      SDK.init();
      await SDK.ready();

      const extCtx = SDK.getExtensionContext();
      const dataService = await SDK.getService<IExtensionDataService>(CommonServiceIds.ExtensionDataService);
      const token = await SDK.getAccessToken();
      const dataManager = await dataService.getExtensionDataManager(extCtx.id, token);

      // inside your onLoaded handler, after you’ve got dataManager:
      try {
      const doc: any = await dataManager.getDocument("configuration", "DefaultDoc");
      // ConfigHub stores your settings under `doc.configuration`
      console.log("🔧 FieldSentinel loaded ConfigHub configuration:", doc.configuration);
      }
      catch (e) {
      console.error("🔧 FieldSentinel could not load ConfigHub configuration:", e);
      }

      // ——————————————————————————————————————————
    },
    onFieldChanged: (fieldChangedArgs: ExtensionContracts.IWorkItemFieldChangedArgs) => {
      let changedValue = fieldChangedArgs.changedFields;
      controller.FieldChanged(changedValue);
    }
  };
};

I can see the configuration being pulled correctly, so the functionality itself seems to work. But I am flooded with error messages and I am hoping that there is a simple fix for this.

Exmple handler messages (happy to upload more info somewhere, if helpful).

VSS.SDK.min.js:2 No handler found on any channel for message: {"id":5,"result":{"id":"DefaultDoc","configuration":{"version":"1","field_sentinel":{}},"__etag":9},"jsonrpc":"2.0"}
n._handleMessageReceived @ VSS.SDK.min.js:2
(anonymous) @ VSS.SDK.min.js:2Understand this error
FieldSentinel.ts:595 🔧 FieldSentinel loaded ConfigHub configuration: {version: '1', field_sentinel: {…}}
XDM.js:501 No handler found on any channel for message: {"id":7,"jsonrpc":"2.0"}

Does anybody know?

I am happy to post my manifest and webpack config, if that is of any use.

Thank you all

Alex


Solution

  • When the SDK logs “No handler found on any channel for message,” it means that behind the scenes every call you make to the host (whether you’re asking for a service or wiring up an event) is sent as a JSON-RPC message across a channel. If you never register a listener on that channel, the incoming messages simply drop through and trigger that console warning.

    "contributions": [
      {
        "id": "my-config-page",
        …
      }
    ]
    
    

    but in your code, you do

    VSS.register("config-page", handler);
    
    

    or vice versa. Since those strings differ, the SDK never wires your handler up to the incoming messages. One easy way to avoid that is to grab the full contribution ID at runtime

    const contribId = VSS.getContribution().id;
    VSS.register(contribId, handler);
    
    

    Just remember that getContribution().id is the namespace-prefixed form (publisher.extension.contribution), so your manifest has to use exactly that same full ID.

    VSS.notifyLoadSucceeded();
    
    

    after the VSS.register(...) call. Skipping the notify step means the host never completes the handshake and the handlers never get connected.

    Once the manifest ID and your register call match, you notify the host that you’re loaded, and you stick with a single SDK instance, those JSON-RPC warnings will disappear.