angular/angular-cli · error

Expected name to be a string.

Error message

Expected name to be a string.

What it means

register() resolves the job name from (in order) options.name, nameOrHandler.jobDescription.name, then handlerOrOptions.name. If all three are undefined the name cannot be determined, and a TypeError is thrown (the message says string even though the check is === undefined).

Source

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

    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.');
    }
  }

  protected _register<
    ArgumentT extends JsonValue,
    InputT extends JsonValue,
    OutputT extends JsonValue,
  >(
    name: JobName,
    handler: JobHandler<ArgumentT, InputT, OutputT>,
    options: RegisterJobOptions,
  ): void {
    if (this._jobNames.has(name)) {

View on GitHub (pinned to bb72145f9a)

Solutions

  1. Add a name to the options: registry.register(handler, { name: 'my-job' }).
  2. Give the handler a name at creation: createJobHandler(fn, { name: 'my-job', description: '...' }) so jobDescription.name is populated.
  3. Verify the handler's jobDescription.name is not undefined (e.g. jobDescription was spread without name).

Example fix

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

Strategy: validation

Validate before calling

const resolvedName = opts?.name ?? handler?.jobDescription?.name ?? opts?.name;
if (typeof resolvedName !== 'string' || resolvedName.length === 0) {
  throw new Error('job name must be provided via options.name or jobDescription.name');
}

Type guard

function hasJobName(handler, opts) {
  return typeof (opts?.name ?? handler?.jobDescription?.name) === 'string';
}

Try / catch

try {
  registry.register(handler, opts);
} catch (e) {
  if (e instanceof TypeError && /Expected name to be a string/.test(e.message)) {
    throw new Error(`job has no name: set options.name or jobDescription.name on the handler`);
  }
  throw e;
}

Prevention

When it happens

Trigger: register(handler, { description: 'x' }) where neither the options object nor the handler's jobDescription carries a name; creating a JobHandler without passing { name: ... } to createJobHandler and not supplying options.name.

Common situations: Constructing handlers manually without jobDescription.name; omitting the name in the options bag while relying on a handler created with an anonymous factory; copies/refactors that stripped the name property.

Related errors


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