paperclipai/paperclip · critical

Persisted Cloud runtime identity contains an invalid origin

Error message

Persisted Cloud runtime identity contains an invalid origin

What it means

After confirming the stack id matches, assertPersistedIdentityMatchesStack validates that both previousOrigin and canonicalOrigin stored in the durable Cloud runtime identity row are exact HTTPS origins: absolute https URLs, no credentials, no path/query/hash, exactly equal to their parsed origin, and at most 2048 chars. If either stored origin fails exactHttpsOrigin, startup throws this error. It prevents a corrupted or tampered persisted identity from driving later URL/env derivation.

Source

Thrown at server/src/services/cloud-runtime-identity.ts:163

      const parsed = JSON.parse(env.PAPERCLIP_RUNTIME_API_CANDIDATES_JSON ?? "[]");
      return Array.isArray(parsed) ? parsed.filter((value): value is string => typeof value === "string") : [];
    } catch {
      return [];
    }
  })();
  env.PAPERCLIP_RUNTIME_API_CANDIDATES_JSON = JSON.stringify([
    identity.canonicalOrigin,
    ...existingCandidates.filter((candidate) => candidate !== identity.canonicalOrigin),
  ]);
}

function assertPersistedIdentityMatchesStack(row: PersistedRuntimeIdentity, env: NodeJS.ProcessEnv) {
  const configuredStackId = nonEmpty(env.PAPERCLIP_CLOUD_STACK_ID);
  if (!configuredStackId || configuredStackId !== row.stackId) {
    throw new Error("Persisted Cloud runtime identity does not match PAPERCLIP_CLOUD_STACK_ID");
  }
  if (!exactHttpsOrigin(row.previousOrigin) || !exactHttpsOrigin(row.canonicalOrigin)) {
    throw new Error("Persisted Cloud runtime identity contains an invalid origin");
  }
  if (!STACK_SLUG_PATTERN.test(row.stackSlug) || new URL(row.canonicalOrigin).hostname.split(".")[0] !== row.stackSlug) {
    throw new Error("Persisted Cloud runtime identity contains an invalid stack slug");
  }
}

/** Load the durable claim before auth, routes, and child-runtime configuration. */
export async function initializeCloudRuntimeIdentity(
  db: Db,
  env: NodeJS.ProcessEnv = process.env,
): Promise<CloudRuntimeIdentitySnapshot | null> {
  startupOrigin = configuredStartupOrigin(env);
  // Self-hosted servers have no Cloud stack identity to restore. Avoid touching
  // the singleton table on that path; besides keeping the feature inert, this
  // preserves lightweight startup/test database seams that intentionally do
  // not construct a database client.
  if (!nonEmpty(env.PAPERCLIP_CLOUD_STACK_ID)) {
    initialized = true;

View on GitHub (pinned to 01ad858492)

Solutions

  1. Inspect the instanceSettings row with singletonKey 'cloud-runtime-identity/v1' and correct previousOrigin/canonicalOrigin to exact bare https origins (e.g. 'https://stack.example.com' — no trailing slash, path, query, or credentials).
  2. If the row is unrecoverable or was written by a failed/aborted claim, remove the row and re-run the one-time identity assertion (applyCloudRuntimeIdentityAssertion) to re-claim cleanly.
  3. Verify no migration or import step lowercased/normalized the URL with a trailing slash or rewrote https to http.

Example fix

// persisted row in instance_settings.general
// before
canonicalOrigin: "https://my-stack.example.com/"
// after
"canonicalOrigin": "https://my-stack.example.com"
Defensive patterns

Strategy: validation

Validate before calling

function isExactHttpsOrigin(value: unknown): boolean {
  if (typeof value !== "string" || !value || value.length > 2048) return false;
  try {
    const u = new URL(value);
    return u.protocol === "https:" && !u.username && !u.password &&
      u.pathname === "/" && !u.search && !u.hash && u.origin === value;
  } catch { return false; }
}
// assert before writing/claiming:
if (!isExactHttpsOrigin(previousOrigin) || !isExactHttpsOrigin(canonicalOrigin)) {
  throw new Error("origins must be exact bare https origins, e.g. https://stack.example.com");
}

Type guard

function isExactHttpsOrigin(value: unknown): value is string {
  if (typeof value !== "string" || !value || value.length > 2048) return false;
  try {
    const u = new URL(value);
    return u.protocol === "https:" && !u.username && !u.password &&
      u.pathname === "/" && !u.search && !u.hash && u.origin === value;
  } catch { return false; }
}

Prevention

When it happens

Trigger: initializeCloudRuntimeIdentity loads a persisted identity row whose previousOrigin or canonicalOrigin fails exactHttpsOrigin: not parseable as a URL, not https scheme, contains username/password, has a path other than '/', has query string or hash, includes a trailing slash or port mismatch so value !== parsed.origin, is empty, or exceeds 2048 characters.

Common situations: The instance_settings row was hand-edited or migrated incorrectly (e.g. stored 'https://example.com/' with trailing slash, or an http:// origin); a partial write or data import corrupted the JSON; an operator set a non-HTTPS internal URL during a manual claim; restoring a DB dump from an environment with differently shaped origins.

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/91c4e89386c2a123. Report an issue: GitHub.