paperclipai/paperclip · error · TeamsServiceUrlValidationError

Teams destination contains an invalid service URL

Error message

Teams destination contains an invalid service URL

What it means

normalizedTeamsServiceUrl parses the serviceUrl with the URL constructor; if parsing fails it throws TeamsServiceUrlValidationError with 'Teams destination contains an invalid service URL'. This rejects strings that are not syntactically valid absolute URLs.

Source

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

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
  ) {
    throw new TeamsServiceUrlValidationError(
      "Teams destination contains an invalid service URL",
    );
  }
  return parsed.toString().replace(/\/+$/, "");
}

function trustedTeamsServiceUrl(

View on GitHub (pinned to 01ad858492)

Solutions

  1. Provide a fully-qualified absolute URL including scheme, e.g. https://smba.trafficmanager.net/.../.
  2. Fix the stored destination record so serviceUrl is the exact value from the Teams activity.
  3. Trim whitespace/control characters that may make the URL unparseable.
  4. Log and inspect the failing value to confirm whether the record was truncated or misconfigured.

Example fix

// before
serviceUrl: "smba.trafficmanager.net/americas"
// after
serviceUrl: "https://smba.trafficmanager.net/americas"
Defensive patterns

Strategy: validation

Validate before calling

let parsed: URL;
try { parsed = new URL(dest.serviceUrl); } catch { throw new Error("serviceUrl is not an absolute URL"); }

Type guard

function isAbsoluteUrl(value: string): boolean {
  try { new URL(value); return true; } catch { return false; }
}

Try / catch

try {
  const url = normalizedTeamsServiceUrl(dest.serviceUrl);
} catch (e) {
  if (e instanceof TeamsServiceUrlValidationError) {
    // log the raw value and require the exact serviceUrl from the Teams activity
  }
}

Prevention

When it happens

Trigger: Calling the Teams destination normalization with a serviceUrl string such as 'not-a-url', 'localhost:3979/api/messages' without scheme prefix issues, or a garbled/truncated string that new URL(value) cannot parse.

Common situations: Hand-edited config where https:// was dropped; a truncated URL from a bad DB write; using a relative path or hostname-only value instead of an absolute URL.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


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