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.

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@3f1d897a7c (2026-09-10). Data as JSON: /api/errors/338945cb30bc3fb4. Report an issue: GitHub.

Appendix: source

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

  ) => 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 3f1d897a7c)