cheeriojs/cheerio · error · TypeError

Bad combination of arguments.

Error message

Bad combination of arguments.

What it means

Cheerio's attr() method only accepts certain argument combinations. When the second argument (value) is a function, the first argument (name) must be a string attribute name. Calling attr() with a function value but a non-string name (e.g. an object map combined with a function) is invalid and throws immediately.

Source

Thrown at src/api/attributes.ts:204

 * @see {@link https://api.jquery.com/attr/}
 */
export function attr<T extends AnyNode>(
  this: Cheerio<T>,
  values: Record<string, string | null>,
): Cheerio<T>;
export function attr<T extends AnyNode>(
  this: Cheerio<T>,
  name?: string | Record<string, string | null>,
  value?:
    | string
    | null
    | ((this: Element, i: number, attrib: string) => string | null),
): string | Cheerio<T> | undefined | Record<string, string> {
  // Set the value (with attr map support)
  if (typeof name === 'object' || value !== undefined) {
    if (typeof value === 'function') {
      if (typeof name !== 'string') {
        throw new TypeError('Bad combination of arguments.');
      }
      return domEach(this, (el, i) => {
        if (isTag(el)) setAttr(el, name, value.call(el, i, el.attribs[name]));
      });
    }
    return domEach(this, (el) => {
      if (!isTag(el)) return;

      if (typeof name === 'object') {
        for (const [objName, objValue] of Object.entries(name)) {
          setAttr(el, objName, objValue);
        }
      } else {
        if (typeof name !== 'string') {
          throw new TypeError('Bad combination of arguments.');
        }
        setAttr(el, name, value ?? null);
      }

View on GitHub (pinned to a1be131f9b)

Solutions

  1. Change the call to pass a string attribute name with the function: attr('href', (i, old) => ...)
  2. If setting multiple attributes, drop the function and pass only the object: attr({href: '...', id: '...'})
  3. Enable TypeScript types so the invalid overload is caught at compile time

Example fix

// before
$('img').attr({ src: 'a.png' }, (i, old) => old);
// after
$('img').attr('src', (i, old) => old);
Defensive patterns

Strategy: type-guard

Validate before calling

const isAttrFnCall = (name: unknown, value: unknown) =>
  typeof value === 'function' ? typeof name === 'string' : typeof name === 'string' || typeof name === 'object';
if (!isAttrFnCall(name, value)) throw new Error('Invalid attr() arguments');

Type guard

function isValidAttrArgs(
  name: unknown,
  value?: unknown,
): name is string | Record<string, string> {
  if (typeof value === 'function') return typeof name === 'string';
  return typeof name === 'string' || (typeof name === 'object' && name !== null);
}

Try / catch

try { $('a').attr(name, value); } catch (e) { if (e instanceof TypeError && e.message === 'Bad combination of arguments.') { /* log and fix args */ } else throw e; }

Prevention

When it happens

Trigger: Calling $('.x').attr({...}, function(){...}) — i.e. passing an object of attributes as the first argument AND a function as the second argument. The function-value overload requires attr(name: string, fn).

Common situations: Copy-pasting between jQuery-style code where option objects and callbacks were mixed; refactoring attr calls and accidentally leaving both an options object and a callback; TypeScript users bypassing types with any.

Related errors


AI-assisted analysis of cheeriojs/cheerio@a1be131f9b (2026-08-28). Data as JSON: /api/errors/164202391ee4c6cb. Report an issue: GitHub.