{"record":{"id":"1a63bbc339ca493f","repo":"affaan-m/ECC","slug":"structured-session-targets-require-a-non-empty-typ","errorCode":null,"errorMessage":"Structured session targets require a non-empty type","messagePattern":"Structured session targets require a non-empty type","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/session-adapters/registry.js","lineNumber":63,"sourceCode":"  if (typeof value !== 'string' || value.trim().length === 0) {\n    throw new Error('Structured session targets require a non-empty string value');\n  }\n\n  return value.trim();\n}\n\nfunction normalizeStructuredTarget(target, context = {}) {\n  if (!target || typeof target !== 'object' || Array.isArray(target)) {\n    return {\n      target,\n      context: { ...context }\n    };\n  }\n\n  const value = coerceTargetValue(target.value);\n  const type = typeof target.type === 'string' ? target.type.trim() : '';\n  if (type.length === 0) {\n    throw new Error('Structured session targets require a non-empty type');\n  }\n\n  const adapterId = target.adapterId || TARGET_TYPE_TO_ADAPTER_ID[type] || context.adapterId || null;\n  const nextContext = {\n    ...context,\n    adapterId\n  };\n\n  if (type === 'claude-history' || type === 'claude-alias') {\n    return {\n      target: `claude:${value}`,\n      context: nextContext\n    };\n  }\n\n  if (type === 'codex-worktree' || type === 'codex') {\n    return {\n      target: `codex:${value}`,","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/session-adapters/registry.js#L45-L81","documentation":"normalizeStructuredTarget validates structured session targets before dispatching them to an adapter. A structured target object must carry a non-empty `type` string, which the registry uses to map the target to the correct session adapter via TARGET_TYPE_TO_ADAPTER_ID. When the type is missing, empty, or only whitespace, the registry cannot determine which adapter should handle the target, so it throws immediately.","triggerScenarios":"Calling registry.select({ value: '...' }) or registry.open({ value: '...' }) with a structured target object that omits the `type` key, sets type: '' , type: '   ' (whitespace-only), or sets type to a non-string such as null, a number, or undefined.","commonSituations":"Deserializing targets from JSON where the type field was dropped or renamed (e.g. 'kind' instead of 'type'); building targets programmatically from user input where an empty form field becomes an empty string; copying examples that pass a plain string target vs a structured object and mixing the two shapes.","solutions":["Add a valid `type` string to the structured target, e.g. { type: 'claude', value: '...' }.","Trim and check the type before calling: if (!target?.type?.trim()) throw/fallback before invoking select/open.","If the value came from persisted JSON, fix the producer/serializer so the type key is emitted, or migrate old records to include it.","If the target is genuinely a plain string, pass the string directly instead of wrapping it as { value: ... }."],"exampleFix":"// before\nregistry.select({ value: 'session-123' });\n\n// after\nregistry.select({ type: 'claude', value: 'session-123' });","handlingStrategy":"validation","validationCode":"function isValidStructuredTarget(t) {\n  return t && typeof t === 'object' && typeof t.type === 'string' && t.type.trim().length > 0 && 'value' in t;\n}\nif (!isValidStructuredTarget(target)) throw new Error('target.type must be a non-empty string');","typeGuard":"const isStructuredTarget = (t) => typeof t === 'object' && t !== null && typeof t.type === 'string' && t.type.trim() !== '';","tryCatchPattern":"try {\n  adapter = registry.select(target, ctx);\n} catch (err) {\n  if (err.message.includes('non-empty type')) {\n    adapter = registry.select({ type: 'claude', value: target.value }, ctx);\n  } else throw err;\n}","preventionTips":["Always construct targets through a factory helper that requires type at build time.","Validate deserialized target JSON against a schema (e.g. z.object({ type: z.string().min(1), value: z.unknown() })) before use.","Never map form/user input straight into target.type without trimming and checking."],"tags":["validation","session-adapters","registry"],"backgroundTag":"empty-required-field","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}