paperclipai/paperclip · error · TeamsServiceUrlValidationError

Teams destination is missing its verified service URL

Error message

Teams destination is missing its verified service URL

What it means

normalizedTeamsServiceUrl validates the serviceUrl of a Microsoft Teams destination before it is used for Bot Connector calls. It throws TeamsServiceUrlValidationError with this message when the value is not a string or exceeds 2048 characters, i.e. the destination has no usable verified service URL at all.

Source

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

  ) => Promise<void>;
  paperclipSendFileCard?: (
    threadId: string,
    kind: "consent" | "file_info",
    card: unknown,
  ) => Promise<{ id: string }>;
  [key: string]: unknown;
}

function teamsConversationRouteStateKey(conversationId: string): string {
  const baseConversationId = conversationId.replace(/;messageid=[^;]+/i, "");
  return `teams:serviceUrl:conversation:${Buffer.from(baseConversationId).toString("base64url")}`;
}

const TEAMS_ACCEPTED_ACTIVITY_CACHE_TTL_MS = 30 * 24 * 60 * 60 * 1_000;

function normalizedTeamsServiceUrl(value: unknown): string {
  if (typeof value !== "string" || value.length > 2048) {
    throw new TeamsServiceUrlValidationError(
      "Teams destination is missing its verified service URL",
    );
  }
  let parsed: URL;
  try {
    parsed = new URL(value);
  } catch {
    throw new TeamsServiceUrlValidationError(
      "Teams destination contains an invalid service URL",
    );
  }
  if (
    parsed.protocol !== "https:" ||
    parsed.username ||
    parsed.password ||
    parsed.search ||
    parsed.hash
  ) {

View on GitHub (pinned to 01ad858492)

Solutions

  1. Ensure the incoming Bot Framework activity's serviceUrl is read and stored before constructing the destination.
  2. Validate presence and typeof serviceUrl === 'string' before calling into the Teams runtime.
  3. Fix the source of the missing/corrupt destination record (re-save from a fresh Teams activity).
  4. Check for field-name typos or schema drift between the stored destination and the expected serviceUrl field.

Example fix

// before
const dest = makeTeamsDestination({ channelData: activity.channelData });
// after
if (typeof activity.serviceUrl !== "string") throw new Error("activity.serviceUrl missing");
const dest = makeTeamsDestination({ serviceUrl: activity.serviceUrl });
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof dest.serviceUrl !== "string" || dest.serviceUrl.length > 2048) {
  throw new Error("destination.serviceUrl missing or too long");
}

Type guard

function hasServiceUrl(dest: unknown): dest is { serviceUrl: string } {
  return typeof dest === "object" && dest !== null &&
    "serviceUrl" in dest && typeof (dest as { serviceUrl: unknown }).serviceUrl === "string";
}

Try / catch

try {
  const url = normalizedTeamsServiceUrl(dest.serviceUrl);
} catch (e) {
  if (e instanceof TeamsServiceUrlValidationError) {
    // re-fetch destination from a fresh Teams activity; do not attempt connector calls
  }
}

Prevention

When it happens

Trigger: Passing undefined/null/non-string (or a string longer than 2048 chars) as the Teams serviceUrl into the normalizedTeamsServiceUrl path of chat-sdk-runtime.ts, typically when constructing a Teams destination from stored conversation data.

Common situations: A Teams activity was saved without serviceUrl; a DB row was corrupted or truncated; code passed a config field name typo so undefined reached the validator; a maliciously crafted payload omitted serviceUrl.

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/338945cb30bc3fb4. Report an issue: GitHub.