{"record":{"id":"33c8ae4f3adaad9f","repo":"ruvnet/ruflo","slug":"invalid-registry-missing-version","errorCode":null,"errorMessage":"Invalid registry: missing version","messagePattern":"Invalid registry: missing version","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/transfer/store/registry.ts","lineNumber":245,"sourceCode":"  return updated;\n}\n\n/**\n * Serialize registry to JSON\n */\nexport function serializeRegistry(registry: PatternRegistry): string {\n  return JSON.stringify(registry, null, 2);\n}\n\n/**\n * Deserialize registry from JSON\n */\nexport function deserializeRegistry(json: string): PatternRegistry {\n  const registry = JSON.parse(json);\n\n  // Validate version\n  if (!registry.version) {\n    throw new Error('Invalid registry: missing version');\n  }\n\n  return registry as PatternRegistry;\n}\n\n/**\n * Sign registry with private key\n */\nexport function signRegistry(registry: PatternRegistry, privateKey: string): PatternRegistry {\n  const content = JSON.stringify({\n    version: registry.version,\n    updatedAt: registry.updatedAt,\n    patterns: registry.patterns.map(p => p.cid),\n    totalPatterns: registry.totalPatterns,\n  });\n\n  // In production: Use actual Ed25519 signing\n  const signature = crypto","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/transfer/store/registry.ts#L227-L263","documentation":"deserializeRegistry() JSON.parses a serialized PatternRegistry and validates that the parsed object has a truthy top-level `version` field before casting it to PatternRegistry. A payload that parses as valid JSON but lacks `version` — `{}`, a CFP pattern document, a truncated/hand-edited file, or data from an incompatible schema — is rejected. Note JSON.parse errors (malformed JSON) throw separately before this check runs.","triggerScenarios":"(1) Feeding a pattern (CFP) file into a code path expecting a registry file; (2) a cached registry.json edited by hand or truncated by a crashed writer; (3) an empty object or different-schema JSON (e.g. `{ patterns: [] }` written without version); (4) version field present but empty string/falsy.","commonSituations":"Two file formats (registry vs pattern) sharing .json extension and getting swapped; scripts generating registry files that forgot the version key; partial downloads cached to disk; schema drift between the tool version that wrote the file and the one reading it.","solutions":["Open the JSON and confirm it is a registry document: it needs a top-level `\"version\"` alongside `\"patterns\"`/`\"updatedAt\"` — if it looks like a single pattern, you are passing the wrong file.","Delete the corrupt/cached registry file and re-download it from the registry source (re-run store.initialize() or the discovery step).","If you generate registries yourself, always include the version field (use serializeRegistry() to write, never hand-rolled JSON.stringify of a partial object).","If the file came from an older tool version, regenerate it with the current version rather than hand-patching."],"exampleFix":"// before\nconst registry = deserializeRegistry(await readFile('cache/registry.json', 'utf8'));\n// cache/registry.json = { \"patterns\": [] } → throws: Invalid registry: missing version\n\n// after\nawait rm('cache/registry.json');               // drop the bad cache\nconst ok = await store.initialize();           // re-download a proper registry\nif (!ok) throw new Error('registry re-fetch failed');","handlingStrategy":"type-guard","validationCode":"import { readFile } from 'node:fs/promises';\nconst text = await readFile(registryPath, 'utf8');\nconst parsed: unknown = JSON.parse(text); // malformed JSON throws here, separately\nif (!isPatternRegistryLike(parsed)) {\n  await rm(registryPath); // drop the bad cache and let discovery re-download\n  throw new Error('registry cache was invalid — removed; re-run initialize()');\n}","typeGuard":"function isPatternRegistryLike(v: unknown): v is { version: string; patterns: unknown[] } {\n  return typeof v === 'object' && v !== null &&\n    typeof (v as { version?: unknown }).version === 'string' && (v as { version?: unknown }).version.length > 0 &&\n    Array.isArray((v as { patterns?: unknown }).patterns);\n}","tryCatchPattern":"try {\n  const registry = deserializeRegistry(json);\n} catch (err) {\n  if (err instanceof SyntaxError) throw new Error('registry file is not valid JSON — re-download it');\n  if (err instanceof Error && err.message === 'Invalid registry: missing version') {\n    throw new Error('wrong or outdated registry file — expected a serialized PatternRegistry with a version field');\n  }\n  throw err;\n}","preventionTips":["Write registries only with serializeRegistry() so the version field can never be omitted","Distinguish file kinds by naming (registry.json vs pattern.cfp.json) so the two never get swapped","Never hand-edit cached registry files; delete and re-download instead","When accepting registries from other tools, run the type guard before deserializeRegistry()"],"tags":["registry","json","schema-validation","deserialization"],"backgroundTag":"schema-validation-failed","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}