{"record":{"id":"46e50833e658b55f","repo":"JuliusBrussee/caveman","slug":"cave-harness-adapter-version-invalid","errorCode":"cave_harness_adapter_version_invalid","errorMessage":"cave_harness_adapter_version_invalid","messagePattern":"cave_harness_adapter_version_invalid","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/agent/src/adapters.ts","lineNumber":90,"sourceCode":"  upstreamVersion: string;\n  bundleSHA256: string;\n  dependencyLockSHA256: string;\n}\n\nexport interface HarnessAdapterManifest extends HarnessAdapterIdentity {\n  schemaVersion: 1;\n  harness: HarnessID;\n  wireContract: Readonly<Record<string, unknown>>;\n}\n\nexport function createHarnessAdapter(\n  id: HarnessID,\n  identity: HarnessAdapterIdentity,\n  wireContract: Readonly<Record<string, unknown>>,\n  invoke: HarnessInvoke,\n): HarnessAdapter {\n  if (!/^[0-9A-Za-z][0-9A-Za-z._-]{0,63}$/.test(identity.adapterVersion)) {\n    throw new Error(\"cave_harness_adapter_version_invalid\");\n  }\n  if (!/^[0-9A-Za-z][0-9A-Za-z._+-]{0,127}$/.test(identity.upstreamVersion)) {\n    throw new Error(\"cave_harness_upstream_version_invalid\");\n  }\n  if (!/^[0-9a-f]{64}$/.test(identity.bundleSHA256) ||\n      !/^[0-9a-f]{64}$/.test(identity.dependencyLockSHA256)) {\n    throw new Error(\"cave_harness_artifact_digest_invalid\");\n  }\n  const manifest = deepFreeze({\n    schemaVersion: 1 as const,\n    harness: id,\n    adapterVersion: identity.adapterVersion,\n    upstreamVersion: identity.upstreamVersion,\n    bundleSHA256: identity.bundleSHA256,\n    dependencyLockSHA256: identity.dependencyLockSHA256,\n    wireContract: canonicalRecord(wireContract),\n  });\n  const contractSHA256 = sha256(stableStringify(manifest));","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/766dce6b1394ebb56a3090748d5a0240a5aefb36/packages/agent/src/adapters.ts#L72-L108","documentation":"`createHarnessAdapter` validates `identity.adapterVersion` against `^[0-9A-Za-z][0-9A-Za-z._-]{0,63}$` before building the frozen adapter manifest. The string must start with an alphanumeric character, contain only letters, digits, `.`, `_`, `-`, and be at most 64 characters — note `+` is NOT allowed here even though it is allowed for `upstreamVersion`. Because the value feeds the contract SHA256 evidence chain, any other shape throws at construction time.","triggerScenarios":"`createVercelAISDKAdapter({ adapterVersion: \"1.2.3+build.42\", ... })`; an empty adapterVersion from a missing build env var; a leading `-` or `.`; a version string longer than 64 characters (e.g. prefixed full digest); whitespace anywhere in the string.","commonSituations":"Reusing a semver string with build metadata (`+sha...`) as the adapter version; CI injecting `VERSION` with trailing newline or spaces; deriving the version from `git describe --dirty` with characters outside the allowed set; hash-based versions exceeding the 64-char cap.","solutions":["Strip `+build` metadata or replace `+` with `-` before constructing the identity","Ensure the first character is alphanumeric and total length is at most 64","Add the same regex as a build-time assert on the version source (package.json field, env var)"],"exampleFix":"// before\ncreateVercelAISDKAdapter({ adapterVersion: pkgVersion /* \"1.0.0+sha.9f2a1c\" */, ... })\n// after\ncreateVercelAISDKAdapter({ adapterVersion: pkgVersion.split('+')[0], ... })","handlingStrategy":"type-guard","validationCode":"const ADAPTER_VERSION_RE = /^[0-9A-Za-z][0-9A-Za-z._-]{0,63}$/;\nconst adapterVersion = pkgVersion.split('+')[0];\nif (!ADAPTER_VERSION_RE.test(adapterVersion)) {\n  throw new Error(`adapterVersion fails identity contract: ${JSON.stringify(adapterVersion)}`);\n}\nreturn createVercelAISDKAdapter({ adapterVersion, ...identity }, agent);","typeGuard":"const ADAPTER_VERSION_RE = /^[0-9A-Za-z][0-9A-Za-z._-]{0,63}$/;\nfunction isValidAdapterVersion(v: unknown): v is string {\n  return typeof v === 'string' && ADAPTER_VERSION_RE.test(v);\n}","tryCatchPattern":"try {\n  return createHarnessAdapter(id, identity, contract, invoke);\n} catch (e) {\n  if (e instanceof Error && e.message === 'cave_harness_adapter_version_invalid') {\n    throw new Error(`build produced an adapterVersion outside [A-Za-z0-9._-]{1,64} (leading alnum): check your version source`);\n  }\n  throw e;\n}","preventionTips":["Derive adapterVersion from a package.json-style semver and strip `+build` metadata","Add a unit test asserting your release version string matches the contract regex","Fail at build time, not adapter-construction time, so bad versions never ship"],"tags":["typescript","validation","versioning","harness-adapter"],"backgroundTag":"invalid-version-string","analyzedSha":"766dce6b1394ebb56a3090748d5a0240a5aefb36","analyzedAt":"2026-08-18T03:14:35.516Z","contentChangedAt":"2026-08-18T03:14:35.516Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}