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
- Add a name to the options: registry.register(handler, { name: 'my-job' }).
- Give the handler a name at creation: createJobHandler(fn, { name: 'my-job', description: '...' }) so jobDescription.name is populated.
- 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
- Always pass { name: 'my-job' } to createJobHandler
- Never spread jobDescription without verifying the name property survives
- Assert handler.jobDescription.name exists in a shared test helper
- Give every registered job an explicit name rather than relying on defaults
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
- Expected a JobHandler as second argument.
- Expected an object options as second argument.
- Unrecognized arguments.
- Could not find the '${builderConf}' builder's node package.
- Cannot determine project for command. This is a multi-projec
AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30).
Data as JSON: /api/errors/44ea9c35e39ed8ac.
Report an issue: GitHub.