{"record":{"id":"9969e0a19ba05eea","repo":"can1357/oh-my-pi","slug":"composer-shape-id-must-be-a-non-empty-trimmed-stri","errorCode":null,"errorMessage":"Composer shape id must be a non-empty trimmed string","messagePattern":"Composer shape id must be a non-empty trimmed string","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/extensibility/extensions/loader.ts","lineNumber":243,"sourceCode":"\t): void {\n\t\tthis.extension.flags.set(name, { name, extensionPath: this.extension.path, ...options });\n\t\tif (options.default !== undefined) {\n\t\t\tthis.runtime.flagValues.set(name, options.default);\n\t\t}\n\t}\n\n\tregisterMessageRenderer<T>(customType: string, renderer: MessageRenderer<T>): void {\n\t\tthis.extension.messageRenderers.set(customType, renderer as MessageRenderer);\n\t}\n\n\tregisterAssistantThinkingRenderer(renderer: AssistantThinkingRenderer): void {\n\t\tthis.extension.assistantThinkingRenderers.push(renderer);\n\t}\n\n\tregisterComposerShape(definition: ComposerShapeDefinition): void {\n\t\tconst id = definition.style.id;\n\t\tif (id.length === 0 || id !== id.trim()) {\n\t\t\tthrow new TypeError(\"Composer shape id must be a non-empty trimmed string\");\n\t\t}\n\t\tif (definition.label.trim().length === 0) {\n\t\t\tthrow new TypeError(`Composer shape \"${id}\" must have a label`);\n\t\t}\n\t\tif (isBuiltinComposerStyle(id)) {\n\t\t\tthrow new Error(`Cannot replace built-in composer shape \"${id}\"`);\n\t\t}\n\t\tthis.extension.composerShapes.set(id, definition);\n\t}\n\n\tgetFlag(name: string): boolean | string | undefined {\n\t\tif (!this.extension.flags.has(name)) return undefined;\n\t\treturn this.runtime.flagValues.get(name);\n\t}\n\n\tsendMessage<T = unknown>(\n\t\tmessage: CustomMessagePayload<T>,\n\t\toptions?: { triggerTurn?: boolean; deliverAs?: \"steer\" | \"followUp\" | \"nextTurn\" },","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/extensibility/extensions/loader.ts#L225-L261","documentation":"registerComposerShape validates that definition.style.id is a non-empty, trimmed string before registering. An empty id, whitespace-only id, or an id with leading/trailing whitespace is rejected with a TypeError.","triggerScenarios":"An extension calls registerComposerShape({ style: { id: '' } }), id: ' myshape ' (leading/trailing spaces), or id from an unparsed/interpolated value that ends up empty.","commonSituations":"Composer shape id built by template concatenation picking up stray spaces; a config-driven id read from JSON/YAML that is blank; interpolation producing empty string when a variable is unset.","solutions":["Trim the id before calling: id: definition.style.id.trim().","Ensure the id is a non-empty constant string in the extension source.","Validate the config-driven id at load time before constructing the ComposerShapeDefinition."],"exampleFix":"// before\napi.registerComposerShape({ style: { id: `prefix-${name} ` }, ... });\n// after\nconst id = `prefix-${name}`.trim();\nif (id) api.registerComposerShape({ style: { id }, ... });","handlingStrategy":"validation","validationCode":"const id = rawId?.trim() ?? '';\nif (id.length === 0) throw new Error('composer shape id required');\napi.registerComposerShape({ style: { id }, ... });","typeGuard":"function isValidShapeId(id: unknown): id is string {\n  return typeof id === 'string' && id.length > 0 && id === id.trim();\n}","tryCatchPattern":"try {\n  api.registerComposerShape(def);\n} catch (err) {\n  if (err instanceof TypeError && err.message.includes('Composer shape id')) {\n    logger.error('invalid composer shape id', { id: def?.style?.id });\n  } else throw err;\n}","preventionTips":["Always .trim() ids built from templates or config.","Define shape ids as constants, never inline interpolated strings.","Validate config-driven ids at extension startup.","Watch for stray whitespace when concatenating prefixes/names."],"tags":["validation","extensions","composer"],"backgroundTag":"schema-validation-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}