vercel/ai · error · HarnessCapabilityUnsupportedError

Custom network policy requires at least one of allowedHosts,

Error message

Custom network policy requires at least one of allowedHosts, allowedCIDRs, or deniedCIDRs to be non-empty.

What it means

toNetworkAccessPolicy validates HarnessV1NetworkPolicy objects with mode 'custom'. A custom policy that specifies none of allowedHosts, allowedCIDRs, or deniedCIDRs would produce an empty custom rule set, which is meaningless and dangerous (it neither allows nor clearly denies anything), so the manager throws HarnessCapabilityUnsupportedError. Use 'allow-all' or 'deny-all' modes for blanket behavior instead.

Source

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

function toNetworkAccessPolicy(
  policy: HarnessV1NetworkPolicy,
): NetworkAccessPolicy {
  switch (policy.mode) {
    case 'allow-all':
      return { mode: 'allow-all' };
    case 'deny-all':
      return { mode: 'deny-all' };
    case 'custom': {
      const allowedHosts = [...(policy.allowedHosts ?? [])];
      const allowedCIDRs = [...(policy.allowedCIDRs ?? [])];
      const deniedCIDRs = [...(policy.deniedCIDRs ?? [])];
      if (
        allowedHosts.length === 0 &&
        allowedCIDRs.length === 0 &&
        deniedCIDRs.length === 0
      ) {
        throw createPolicyConflictError(
          'Custom network policy requires at least one of allowedHosts, allowedCIDRs, or deniedCIDRs to be non-empty.',
        );
      }
      return {
        mode: 'custom',
        allowedHosts,
        allowedCIDRs,
        deniedCIDRs,
      };
    }
  }
}

function composeNetworkPolicy({
  accessPolicy,
  requestTransformations,
  forwardRules,
}: {

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Provide at least one entry: add hostnames to allowedHosts, or CIDR ranges to allowedCIDRs/deniedCIDRs.
  2. If you intend to allow all traffic, pass { mode: 'allow-all' } instead of an empty custom policy.
  3. If you intend to block all traffic, pass { mode: 'deny-all' }.
  4. Validate your config before constructing the policy so empty lists fall back to an explicit mode.

Example fix

// before
await manager.setNetworkPolicy({ mode: 'custom', allowedHosts: [], allowedCIDRs: [], deniedCIDRs: [] });
// after
await manager.setNetworkPolicy({ mode: 'custom', allowedHosts: ['api.example.com'] });
Defensive patterns

Strategy: validation

Validate before calling

function validateNetworkPolicy(policy: { mode: string; allowedHosts?: string[]; allowedCIDRs?: string[]; deniedCIDRs?: string[] }) {
  if (policy.mode !== 'custom') return; // allow-all / deny-all are fine
  const empty =
    (policy.allowedHosts ?? []).length === 0 &&
    (policy.allowedCIDRs ?? []).length === 0 &&
    (policy.deniedCIDRs ?? []).length === 0;
  if (empty) throw new Error('custom policy needs allowedHosts, allowedCIDRs, or deniedCIDRs');
}
validateNetworkPolicy(policy);
await manager.setNetworkPolicy(policy);

Type guard

function isUsableCustomPolicy(p: { mode: string; allowedHosts?: readonly string[]; allowedCIDRs?: readonly string[]; deniedCIDRs?: readonly string[] }): boolean {
  return p.mode !== 'custom' ||
    (p.allowedHosts?.length ?? 0) + (p.allowedCIDRs?.length ?? 0) + (p.deniedCIDRs?.length ?? 0) > 0;
}

Try / catch

try {
  await manager.setNetworkPolicy(policy);
} catch (error) {
  if (error instanceof HarnessCapabilityUnsupportedError && /requires at least one of/.test(error.message)) {
    await manager.setNetworkPolicy({ mode: 'deny-all' }); // safe explicit fallback
  } else throw error;
}

Prevention

When it happens

Trigger: Calling setNetworkPolicy({ mode: 'custom' }) where allowedHosts, allowedCIDRs, and deniedCIDRs are all undefined, null, or empty arrays.

Common situations: Building the policy object dynamically from config/env where all lists end up empty; a refactor that renamed fields so the intended values no longer populate the expected keys; copying an example and forgetting to fill allowedHosts.

Related errors


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