FuelLabs/fuels-ts · error · FuelError

DUPLICATED_POLICY

DUPLICATED_POLICY

Error message

Duplicate policy type found: ${PolicyType.MaxFee}

What it means

Thrown by validateDuplicatedPolicies() when two or more policies in the supplied array share the same PolicyType. Each policy type may appear at most once in a transaction's policy list. NOTE a message bug: the text always interpolates PolicyType.MaxFee (a constant) regardless of which type actually duplicated, so 'MaxFee' in the message may be misleading.

Source

Thrown at packages/transactions/src/coders/policy.ts:62

export type PolicyMaxFee = {
  type: PolicyType.MaxFee;
  data: BN;
};

export type PolicyOwner = {
  type: PolicyType.Owner;
  data: BN;
};

export const sortPolicies = (policies: Policy[]): Policy[] =>
  policies.sort((a, b) => a.type - b.type);

function validateDuplicatedPolicies(policies: Policy[]): void {
  const seenTypes = new Set<PolicyType>();

  policies.forEach((policy) => {
    if (seenTypes.has(policy.type)) {
      throw new FuelError(
        ErrorCode.DUPLICATED_POLICY,
        `Duplicate policy type found: ${PolicyType.MaxFee}`
      );
    }
    seenTypes.add(policy.type);
  });
}

export function getPolicyTypesArray(policyTypes: number): number[] {
  const out: number[] = [];
  let m = policyTypes >>> 0;
  while (m !== 0) {
    const low = m & -m;
    out.push(low);
    m &= m - 1;
  }
  return out;
}

View on GitHub (pinned to b3f37c91ac)

Solutions

  1. Dedupe policies by type before encoding (keep the last/merged value per type).
  2. Inspect the full policies array rather than trusting the 'MaxFee' label in the message, since the message is hardcoded.
  3. Build policies through a single source/map keyed by PolicyType to avoid accidental duplicates.

Example fix

// before
const policies = [
  { type: PolicyType.MaxFee, data: bn(100) },
  { type: PolicyType.MaxFee, data: bn(200) },
];

// after — dedupe by type
const byType = new Map(policies.map(p => [p.type, p]));
const deduped = [...byType.values()];
Defensive patterns

Strategy: validation

Validate before calling

import { PolicyType, type Policy } from '@fuel-ts/transactions';

function dedupePolicies(policies: Policy[]): Policy[] {
  const map = new Map<PolicyType, Policy>();
  for (const p of policies) map.set(p.type, p); // last wins
  return [...map.values()];
}

const clean = dedupePolicies(policies);

Type guard

function hasUniquePolicyTypes(policies: Policy[]): boolean {
  return new Set(policies.map(p => p.type)).size === policies.length;
}

Try / catch

try {
  validateDuplicatedPolicies(policies);
} catch (e) {
  if (e instanceof FuelError && e.code === ErrorCode.DUPLICATED_POLICY) {
    // NOTE: message always says 'MaxFee'; dedupe by actual type and retry
    policies = dedupePolicies(policies);
  } else throw e;
}

Prevention

When it happens

Trigger: Passing a policies array with two entries of the same type, e.g. [{type: PolicyType.MaxFee,...},{type: PolicyType.MaxFee,...}] or two Tip policies; building policies from a map/list without deduping by type.

Common situations: Merging policy lists from multiple sources that both set MaxFee/Tip; default policy plus a user override both present; programmatically pushing a policy that already exists.

Related errors


AI-assisted analysis of FuelLabs/fuels-ts@b3f37c91ac (2026-08-12). Data as JSON: /api/errors/dee2311524c9c567. Report an issue: GitHub.