angular/angular-cli · error

Expected a JobHandler as second argument.

Error message

Expected a JobHandler as second argument.

What it means

SimpleJobRegistry.register() accepts either a job name string plus a handler, or a bare JobHandler object. When the first argument is a string, the second argument must be a valid JobHandler; this TypeError is thrown when isJobHandler(handlerOrOptions) fails, i.e. the second argument is not a function/object with the expected job-handler shape.

Source

Thrown at packages/angular_devkit/architect/src/jobs/simple-registry.ts:76

   * @param handler The function that will be called for the job.
   * @param options An optional list of options to override the handler. {@see RegisterJobOptions}
   */
  register<ArgumentT extends JsonValue, InputT extends JsonValue, OutputT extends JsonValue>(
    handler: JobHandler<ArgumentT, InputT, OutputT>,
    // This version MUST contain a name.
    options?: RegisterJobOptions & { name: string },
  ): void;

  register<ArgumentT extends JsonValue, InputT extends JsonValue, OutputT extends JsonValue>(
    nameOrHandler: JobName | JobHandler<ArgumentT, InputT, OutputT>,
    handlerOrOptions: JobHandler<ArgumentT, InputT, OutputT> | RegisterJobOptions = {},
    options: RegisterJobOptions = {},
  ): void {
    // Switch on the arguments.
    if (typeof nameOrHandler == 'string') {
      if (!isJobHandler(handlerOrOptions)) {
        // This is an error.
        throw new TypeError('Expected a JobHandler as second argument.');
      }

      this._register(nameOrHandler, handlerOrOptions, options);
    } else if (isJobHandler(nameOrHandler)) {
      if (typeof handlerOrOptions !== 'object') {
        // This is an error.
        throw new TypeError('Expected an object options as second argument.');
      }

      const name = options.name || nameOrHandler.jobDescription.name || handlerOrOptions.name;
      if (name === undefined) {
        throw new TypeError('Expected name to be a string.');
      }

      this._register(name, nameOrHandler, options);
    } else {
      throw new TypeError('Unrecognized arguments.');
    }

View on GitHub (pinned to bb72145f9a)

Solutions

  1. Pass a valid JobHandler (created via createJobHandler) as the second argument: registry.register('my-job', createJobHandler(() => ..., { name: 'my-job' })).
  2. Check argument order: register(name, handler, options) — swap the second and third arguments if an options object was passed second.
  3. If registering a bare handler, drop the string and call register(handler) or register(handler, { name: 'my-job' }) so the name is inferred from jobDescription.name.
  4. Log or inspect the second argument's type just before the call to confirm it is the handler, not a Promise resolving to one (await it first).

Example fix

// before
registry.register('build-job', { name: 'build-job', description: 'build' });
// after
registry.register('build-job', createJobHandler(() => of({ success: true }), { name: 'build-job', description: 'build' }));
Defensive patterns

Strategy: type-guard

Validate before calling

const { isJobHandler } = require('@angular-devkit/architect');
if (typeof nameOrHandler === 'string' && !isJobHandler(handlerOrOptions)) {
  throw new Error('second argument must be a JobHandler');
}

Type guard

function isHandler(v) {
  return v != null && (typeof v === 'function' || (typeof v === 'object' && typeof v.handler === 'function' && v.jobDescription && typeof v.jobDescription.name === 'string'));
}

Try / catch

try {
  registry.register(name, handler);
} catch (e) {
  if (e instanceof TypeError && /JobHandler as second argument/.test(e.message)) {
    throw new Error(`register('${name}') got a non-handler second argument: ${typeof handler}`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling registry.register('job-name', <something that is not a JobHandler>) — e.g. passing the wrong variable, a plain function missing jobDescription/argument/input/output properties, or passing the options object as the second argument by mistake.

Common situations: Passing arguments in the wrong order (name, options, handler) instead of (name, handler, options); passing a plain callback from an older job API after an Angular DevKit version change; refactoring that replaced a handler with a factory return value.

Understand the failure class

Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30). Data as JSON: /api/errors/de52884edc518424. Report an issue: GitHub.