{"record":{"id":"c808e93b5822962b","repo":"affaan-m/ECC","slug":"invalid-plan-canvas-session-key","errorCode":null,"errorMessage":"invalid plan-canvas session key","messagePattern":"invalid plan-canvas session key","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/plan-canvas.js","lineNumber":246,"sourceCode":"  const res = await request(port, 'POST', '/api/sessions', {\n    file: path.resolve(file),\n    reopen: args.includes('--reopen')\n  });\n  if (res.statusCode === 409) return res.body;\n  if (res.statusCode !== 200) throw new Error(res.body.error || `open failed (HTTP ${res.statusCode})`);\n  const url = `http://${DEFAULT_HOST}:${port}${res.body.url}`;\n  const launched = args.includes('--no-open') ? false : openBrowser(url);\n  return {\n    status: 'open',\n    url,\n    browser: launched ? 'opened' : 'not opened',\n    next_step:\n      'Run `ecc-plan-canvas await <file>` and leave it running; it returns when the human sends feedback, a verdict, or ends the session.'\n  };\n}\n\nfunction awaitRequest(port, key, timeoutMs) {\n  if (!/^[a-f0-9]{12}$/.test(key)) throw new Error('invalid plan-canvas session key');\n  const params = new URLSearchParams({ key });\n  if (timeoutMs !== null) params.set('timeoutMs', String(timeoutMs));\n  return new Promise((resolve, reject) => {\n    const req = http.request(\n      requestOptions(port, 'GET', `/api/await?${params}`, {}),\n      res => {\n        let data = '';\n        res.on('data', chunk => {\n          data += chunk;\n        });\n        res.on('end', () => {\n          try {\n            resolve(JSON.parse(data.trim()));\n          } catch {\n            reject(new Error('await response was not JSON (server restarted?) - re-run await; feedback is never lost'));\n          }\n        });\n      }","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/plan-canvas.js#L228-L264","documentation":"Thrown by awaitRequest in scripts/plan-canvas.js when the session key does not match the strict pattern `/^[a-f0-9]{12}$/` — exactly 12 lowercase hex characters. Session keys are derived from the artifact path via sessionKeyFor, so a mismatch implies the caller passed a raw/arbitrary string or the derivation produced an unexpected value.","triggerScenarios":"Calling awaitRequest directly (internal) with a key that is not 12 lowercase hex chars; an uppercase hex key; a key of the wrong length; passing a filename or path where a key is expected. In normal CLI flow cmdAwait computes the key via sessionKeyFor(canonicalizeArtifactPath(file)), so this guard is a defensive check on that derivation.","commonSituations":"A change to sessionKeyFor or canonicalizeArtifactPath that alters the key format; calling the internal request layer with a user-supplied identifier; a test fixture using a placeholder key like 'test' or 'session-1'.","solutions":["Always derive the key with sessionKeyFor(canonicalizeArtifactPath(file)) rather than constructing one by hand.","If you maintain sessionKeyFor, ensure it still emits 12 lowercase hex characters.","End users hitting this via the CLI: it signals a bug in path canonicalization — report it with the file path used."],"exampleFix":"// before (internal call, raw id)\nawaitRequest(port, 'session-1', null);\n// after\nconst key = sessionKeyFor(canonicalizeArtifactPath(file));\nawaitRequest(port, key, null);","handlingStrategy":"type-guard","validationCode":"const KEY_RE = /^[a-f0-9]{12}$/;\nfunction assertSessionKey(key) {\n  if (!KEY_RE.test(key)) throw new Error(`Invalid session key (need 12 lowercase hex chars): ${String(key)}`);\n  return key;\n}","typeGuard":"function isSessionKey(value) {\n  return typeof value === 'string' && /^[a-f0-9]{12}$/.test(value);\n}","tryCatchPattern":null,"preventionTips":["Always derive keys with sessionKeyFor(canonicalizeArtifactPath(file)); never construct them by hand.","If you change sessionKeyFor or canonicalizeArtifactPath, regenerate existing fixtures and migration tests.","End users: treat this as a CLI bug and report the file path that triggered it."],"tags":["plan-canvas","validation","internal-api","session"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}