{"record":{"id":"ec6e47160d41b708","repo":"angular/angular-cli","slug":"workspace-extension-with-invalid-name-name-fo","errorCode":null,"errorMessage":"Workspace extension with invalid name (${name}) found.","messagePattern":"Workspace extension with invalid name \\((.+?)\\) found\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/angular_devkit/core/src/workspace/json/reader.ts","lineNumber":118,"sourceCode":"  }\n\n  // TODO: `getNodeValue` - looks potentially expensive since it walks the whole tree and instantiates the full object structure each time.\n  // Might be something to look at moving forward to optimize.\n  const workspaceNodeValue = getNodeValue(workspaceNode);\n  for (const [name, value] of Object.entries<JsonValue>(workspaceNodeValue)) {\n    if (name === '$schema' || name === 'version') {\n      // skip\n    } else if (name === 'projects') {\n      const nodes = findNodeAtLocation(workspaceNode, ['projects']);\n      if (!isJsonObject(value) || !nodes) {\n        context.error('Invalid \"projects\" field found; expected an object.', value);\n        continue;\n      }\n\n      projects = parseProjectsObject(nodes, context);\n    } else {\n      if (!context.unprefixedWorkspaceExtensions.has(name) && !/^[a-z]{1,3}-.*/.test(name)) {\n        context.warn(`Workspace extension with invalid name (${name}) found.`, name);\n      }\n      if (extensions) {\n        extensions[name] = value;\n      }\n    }\n  }\n\n  let collectionListener: DefinitionCollectionListener<ProjectDefinition> | undefined;\n  if (context.trackChanges) {\n    collectionListener = (name, newValue) => {\n      jsonMetadata.addChange(['projects', name], newValue, 'project');\n    };\n  }\n\n  const projectCollection = new ProjectDefinitionCollection(projects, collectionListener);\n\n  return {\n    [JsonWorkspaceSymbol]: jsonMetadata,","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/angular/angular-cli/blob/bb72145f9ab45aee29f523236b3a25cd0813a841/packages/angular_devkit/core/src/workspace/json/reader.ts#L100-L136","documentation":"While parsing angular.json, the workspace reader warns when a top-level key is treated as a workspace extension but its name is neither a known unprefixed extension nor matches the required 'aaa-*' (1-3 lowercase letters followed by a dash) prefix convention.","triggerScenarios":"parseWorkspace encounters a top-level key outside the reserved set (version, projects, etc.) whose name fails /^[a-z]{1,3}-.*/ and is not in unprefixedWorkspaceExtensions (e.g. 'myExtension' or 'CLI_config').","commonSituations":"Hand-edited angular.json adding custom config keys at the root; tools writing vendor settings into the wrong file; typos in known extension names (e.g. 'schemetics' instead of 'schematics').","solutions":["Rename the key to the namespaced form 'xxx-name' (1-3 lowercase letters, a dash, then the name), e.g. 'x-custom' or 'nx-custom'.","If it was a typo of a built-in extension (cli, schematics, etc.), correct the spelling.","Move unrelated settings out of angular.json into a separate config file."],"exampleFix":"// before (angular.json)\n{ \"version\": 1, \"myConfig\": {} }\n// after\n{ \"version\": 1, \"x-myConfig\": {} }","handlingStrategy":"validation","validationCode":"const RESERVED = new Set(['version', 'projects', 'cli', 'schematics', 'newProjectRoot', 'defaultProject']);\nconst json = require('./angular.json');\nfor (const key of Object.keys(json)) {\n  if (!RESERVED.has(key) && !/^[a-z]{1,3}-.*/.test(key)) {\n    console.warn(`Invalid workspace extension name: ${key} (use 'xxx-name' form)`);\n  }\n}","typeGuard":"function isValidExtensionName(name) {\n  return /^[a-z]{1,3}-.*/.test(name);\n}","tryCatchPattern":null,"preventionTips":["Namespace all custom workspace keys as 'vendor-name' (1-3 lowercase letters + dash).","Never hand-edit angular.json without validating against the schema (`ng` validates on load).","Keep third-party tool settings in their own config files when possible."],"tags":["angular","workspace-configuration","angular-json","naming"],"backgroundTag":"invalid-extension-name","analyzedSha":"bb72145f9ab45aee29f523236b3a25cd0813a841","analyzedAt":"2026-08-30T02:47:34.745Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}