{"record":{"id":"8f28a8f04a691379","repo":"affaan-m/ECC","slug":"createplancanvasserver-requires-a-session-store","errorCode":null,"errorMessage":"createPlanCanvasServer requires a session store","messagePattern":"createPlanCanvasServer requires a session store","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/lib/plan-canvas/server.js","lineNumber":126,"sourceCode":"      \"default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; frame-src 'self'\";\n  }\n  res.writeHead(statusCode, headers);\n  res.end(html);\n}\n\nfunction createPlanCanvasServer({\n  store,\n  host = DEFAULT_HOST,\n  version = '0.0.0',\n  idleTimeoutMs = DEFAULT_IDLE_TIMEOUT_MS,\n  heartbeatMs = 15000,\n  thinkingStaleMs = DEFAULT_THINKING_STALE_MS,\n  typingExpiryMs = DEFAULT_TYPING_EXPIRY_MS,\n  presenceSweepMs = DEFAULT_PRESENCE_SWEEP_MS,\n  onIdleShutdown = null,\n  log = () => {}\n} = {}) {\n  if (!store) throw new Error('createPlanCanvasServer requires a session store');\n\n  const allowedHostnames = buildAllowedHostnames(host);\n  const wake = new EventEmitter();\n  wake.setMaxListeners(0);\n  const sseClients = new Map(); // key -> Set<res>\n  const awaitCounts = new Map(); // key -> active long-poll count\n  const workingKeys = new Map(); // key -> ms timestamp the agent took feedback\n  const typingKeys = new Map(); // key -> ms timestamp the agent signalled composing\n  const watchers = new Map(); // key -> fs.FSWatcher\n  const lastPresence = new Map(); // key -> last broadcast state, for sweep diffing\n  let idleTimer = null;\n  let presenceSweep = null;\n  let closed = false;\n\n  // --- presence + SSE ---------------------------------------------------\n\n  /**\n   * Presence never claims more than the server actually knows:","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/plan-canvas/server.js#L108-L144","documentation":"createPlanCanvasServer() constructs the Plan Canvas HTTP/SSE server and requires a session store — the object that persists session, feedback, and presence state. If the store parameter is missing or falsy the factory throws immediately rather than starting a server with no persistence. It is a constructor-time guard so misconfiguration surfaces at startup, not on first request.","triggerScenarios":"Calling createPlanCanvasServer() with no arguments; passing an options object without a store key ({ host, port, ... } but no store); passing store: null/undefined after a failed store initialization (e.g. store factory returned null).","commonSituations":"Wiring up the canvas server in a custom launcher and forgetting to create the store (e.g. new FileSessionStore(...) or equivalent) first; destructuring config where the store field is absent; a store module failing to load and silently yielding undefined.","solutions":["Create and pass a session store: createPlanCanvasServer({ store: new FileSessionStore(dir) }) (use the store implementation your setup documents).","Check the call site for a typo'd or missing 'store' key in the options object.","Verify the store factory/instantiation did not fail and return undefined — log its value before the call.","Follow the library's documented bootstrap (e.g. the canvas command in scripts) instead of hand-rolling the factory call."],"exampleFix":"// before\nconst server = createPlanCanvasServer({ port: 4111 });\n// after\nconst store = new FileSessionStore(stateDir);\nconst server = createPlanCanvasServer({ port: 4111, store });","handlingStrategy":"validation","validationCode":"if (!store) {\n  throw new Error('Plan Canvas: create the session store before createPlanCanvasServer.');\n}\nconst server = createPlanCanvasServer({ ...opts, store });","typeGuard":"function hasSessionStore(opts) {\n  return Boolean(opts && opts.store && typeof opts.store === 'object');\n}","tryCatchPattern":"try {\n  const server = createPlanCanvasServer(opts);\n} catch (e) {\n  if (e.message === 'createPlanCanvasServer requires a session store') {\n    console.error('Options object is missing `store` — construct the store (e.g. new FileSessionStore(dir)) and pass it.');\n  } else throw e;\n}","preventionTips":["Instantiate the session store first and pass it explicitly in the options object.","Check that the store factory did not fail and silently return undefined/null.","Keep server bootstrap in one reviewed launcher script rather than ad-hoc invocations.","Add a startup smoke test that constructs the server with a temp store."],"tags":["configuration","missing-argument","server","initialization"],"backgroundTag":"missing-required-argument","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"}