paperclipai/paperclip · error · TeamsServiceUrlValidationError

Teams destination is missing its conversation identity

Error message

Teams destination is missing its conversation identity

What it means

withThreadServiceUrl decodes a Paperclip thread id back into Teams coordinates and requires a non-empty conversationId, because all outbound calls must be routed to the conversation's persisted or decoded service URL. If decodeThreadId yields no conversation identity, the destination is unusable and TeamsServiceUrlValidationError is thrown.

Source

Thrown at server/src/services/chat-sdk-runtime.ts:1195

      serviceUrl: string,
      http: unknown,
      settings?: unknown,
    ) => TeamsApiClientInternals;
    const scopedApi = new ApiClient(
      serviceUrl,
      defaultApi.http,
      defaultApi._apiClientSettings,
    );
    return await apiScope.run(scopedApi, operation);
  };
  const withThreadServiceUrl = async <T>(
    threadId: string,
    operation: () => Promise<T>,
    requireRoute = false,
  ): Promise<T> => {
    const decoded = teams.decodeThreadId!(threadId);
    if (typeof decoded.conversationId !== "string" || !decoded.conversationId) {
      throw new TeamsServiceUrlValidationError(
        "Teams destination is missing its conversation identity",
      );
    }
    const persistedServiceUrl = await teams.chat
      ?.getState()
      .get(teamsConversationRouteStateKey(decoded.conversationId));
    if (
      requireRoute &&
      persistedServiceUrl == null &&
      decoded.serviceUrl == null
    ) {
      throw new TeamsServiceUrlValidationError(
        "Teams file destination is missing its verified route",
      );
    }
    return await withServiceUrl(
      persistedServiceUrl ?? decoded.serviceUrl ?? defaultApi.serviceUrl,
      operation,

View on GitHub (pinned to 01ad858492)

Solutions

  1. Verify the threadId originates from the Teams adapter (teams.decodeThreadId should round-trip it) and is not empty.
  2. Log the decoded object to inspect what decodeThreadId returns for your id format.
  3. Migrate any persisted legacy ids so they carry a conversation identity.
  4. Guard call sites: only invoke Teams outbound APIs with ids produced by the Teams adapter's encodeThreadId.

Example fix

// before
await sendTeamsMessage(someOtherAdapterThreadId, text); // foreign id
// after
if (!threadId?.startsWith('teams:')) return;
await sendTeamsMessage(threadId, text); // Teams-adapter-issued id with conversationId
Defensive patterns

Strategy: validation

Validate before calling

const decoded = teams.decodeThreadId(threadId);
if (typeof decoded?.conversationId !== 'string' || !decoded.conversationId) {
  throw new Error(`threadId ${threadId} has no Teams conversation identity`);
}

Type guard

function isTeamsThreadId(threadId: string): boolean {
  try { return Boolean(teams.decodeThreadId(threadId)?.conversationId); } catch { return false; }
}

Try / catch

try {
  await sendViaTeams(threadId, payload);
} catch (err) {
  if (err instanceof TeamsServiceUrlValidationError && err.message.includes('conversation identity')) {
    logger.warn(`Skipping non-Teams or malformed threadId: ${threadId}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling any thread-scoped outbound operation (send, postActivity, file card send, etc.) with a threadId whose decoded form has no conversationId — e.g. a malformed/legacy thread id, a non-Teams id passed into a Teams path, or an empty string id.

Common situations: Storing thread ids from a different chat adapter and passing them to Teams egress; truncating or corrupting persisted thread ids in your own database; legacy thread-id formats that decodeThreadId cannot parse into a conversation id.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/0545c1842ad8e899. Report an issue: GitHub.