vercel/ai · error · HarnessCapabilityUnsupportedError

Cannot add request transformations because the current Verce

Error message

Cannot add request transformations because the current Vercel Sandbox policy contains request transformations that cannot be attributed to this call. Their header values are redacted, so preserving them safely is not possible.

What it means

addRequestTransformations() on an uninitialized manager (no private state) must attribute transformations already present in the live Vercel policy. Because Vercel redacts transformed header values on read-back, existing transformations can only be matched by their materialized hosts. If the live policy has transformation hosts that are NOT covered by the hosts implied by the incoming transformations, the manager cannot tell which are yours and refuses with HarnessCapabilityUnsupportedError to avoid corrupting them.

Source

Thrown at packages/sandbox-vercel/src/vercel-network-policy-manager.ts:128

          requestTransformations: incomingTransformations,
          forwardRules: inspection.forwardRules,
        });
        const incomingHosts = getRequestTransformationHosts(incomingPolicy);

        /*
         * Vercel redacts transformed header values when a policy is read back.
         * It can also normalize rule details, so initialization and resume can
         * only attribute existing transformations by their materialized hosts.
         * External transformations for the same hosts are indistinguishable
         * and are necessarily treated as managed by this call.
         */
        if (
          !isHostSetSubset({
            subset: inspection.requestTransformationHosts,
            superset: incomingHosts,
          })
        ) {
          throw createPolicyConflictError(
            'Cannot add request transformations because the current Vercel Sandbox policy contains request transformations that cannot be attributed to this call. Their header values are redacted, so preserving them safely is not possible.',
          );
        }
      }

      await this.#applyState({
        accessPolicy: inspection.accessPolicy,
        requestTransformations:
          this.#state == null
            ? incomingTransformations
            : mergeRequestTransformations({
                existing: this.#state.requestTransformations,
                incoming: incomingTransformations,
              }),
        forwardRules: inspection.forwardRules.map(cloneForwardRule),
        currentPolicy: inspection.currentPolicy,
      });
    });

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Include transformations covering all existing transformation hosts in the incoming set (so incomingHosts is a superset of the live hosts), then call addRequestTransformations().
  2. Use setRequestTransformations() instead to explicitly declare the complete desired set, replacing whatever exists.
  3. Inspect sandbox.currentSession().networkPolicy to list existing transformation hosts and decide whether to adopt or replace them.
  4. If the stale transformations are unwanted, replace the policy wholesale with setRequestTransformations([]) plus your new entries.

Example fix

// before: only covers api.example.com while policy also has cdn.example.com transformations
await manager.addRequestTransformations([{ host: 'api.example.com', setHeaders: { 'x-key': '...' } }]);
// after: cover all existing hosts, or declare full set
await manager.setRequestTransformations([
  { host: 'api.example.com', setHeaders: { 'x-key': '...' } },
  { host: 'cdn.example.com', setHeaders: { 'x-key': '...' } },
]);
Defensive patterns

Strategy: validation

Validate before calling

// ensure incoming transformation hosts cover all existing ones before adding
function transformationHostsFromPolicy(p: unknown): string[] {
  if (p == null || typeof p !== 'object') return [];
  return ((p as any).rules ?? [])
    .flatMap((r: any) => (r.requestTransformations ?? []).map(() => r.host))
    .filter(Boolean);
}
const existing = transformationHostsFromPolicy(sandbox.currentSession().networkPolicy);
const incoming = new Set(transformations.map(t => t.host));
if (!existing.every(h => incoming.has(h))) {
  // use setRequestTransformations() to replace, or extend incoming set
  await manager.setRequestTransformations(transformations);
} else {
  await manager.addRequestTransformations(transformations);
}

Type guard

function canAttributeTransformations(existingHosts: readonly string[], incomingHosts: readonly string[]): boolean {
  const set = new Set(incomingHosts);
  return existingHosts.every(h => set.has(h));
}

Try / catch

try {
  await manager.addRequestTransformations(transformations);
} catch (error) {
  if (error instanceof HarnessCapabilityUnsupportedError) {
    // fall back to full explicit replacement
    await manager.setRequestTransformations(transformations);
  } else throw error;
}

Prevention

When it happens

Trigger: First mutation on a fresh VercelNetworkPolicyManager is addRequestTransformations(), while sandbox.currentSession().networkPolicy contains request transformations for hosts outside the set of hosts derivable from the incoming transformations (isHostSetSubset fails).

Common situations: Resuming a sandbox that already has transformations for other hosts (from a prior deployment/run); adding transformations for a narrower host list than what exists; direct @vercel/sandbox policy edits that added extra transformation rules behind the manager's back.

Related errors


AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/2c1ad94e47f338e3. Report an issue: GitHub.