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
- Provide at least one entry: add hostnames to allowedHosts, or CIDR ranges to allowedCIDRs/deniedCIDRs.
- If you intend to allow all traffic, pass { mode: 'allow-all' } instead of an empty custom policy.
- If you intend to block all traffic, pass { mode: 'deny-all' }.
- 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
- Use 'allow-all' or 'deny-all' modes when you don't need fine-grained rules.
- Load policy lists from config with explicit defaults and assert non-emptiness for custom mode.
- Add a unit test asserting isUsableCustomPolicy for every policy your app constructs.
- Watch for refactors that rename allowedHosts/allowedCIDRs/deniedCIDRs and silently leave them empty.
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
- Invalid argument for parameter output: Invalid output type.
- Continuation maxAgeMs must be a positive integer.
- ACP credentialEnv and credentialBrokering must be configured
- Unsupported ACP protocol version ${JSON.stringify(version)}.
- ACP credentialEnv and credentialBrokering must be configured
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/7fbbb6a1fe661aa6.
Report an issue: GitHub.