{"record":{"id":"ac205db5ea1b00af","repo":"affaan-m/ECC","slug":"message-verify-install-plan","errorCode":null,"errorMessage":"message","messagePattern":"message","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"docker/plugin-setup/verify-install-plan.js","lineNumber":9,"sourceCode":"#!/usr/bin/env node\n\n'use strict';\n\nconst fs = require('fs');\nconst path = require('path');\n\nfunction fail(message) {\n  throw new Error(message);\n}\n\nfunction isWithin(root, candidate) {\n  const relative = path.relative(root, candidate);\n  return relative === '' || (\n    relative !== '..'\n    && !relative.startsWith(`..${path.sep}`)\n    && !path.isAbsolute(relative)\n  );\n}\n\nfunction validatePlan(payload, projectDir, requireDryRun) {\n  const expectedRoot = path.resolve(projectDir, '.claude');\n  if (!payload || typeof payload !== 'object' || !payload.plan) {\n    fail('Install output is missing a plan.');\n  }\n  if (requireDryRun && payload.dryRun !== true) {\n    fail('Install plan did not report dryRun=true.');","sourceCodeStart":1,"sourceCodeEnd":27,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/docker/plugin-setup/verify-install-plan.js#L1-L27","documentation":"assertMemoryRootSafe looks up roots[scope] and requires it to be a non-empty string path. If the scope key is absent or its value is empty/not a string, the vault cannot know where to store memory for that scope and throws this error naming the scope. This is thrown before any filesystem access occurs.","triggerScenarios":"Requesting a scope (e.g. 'personal', 'project') that is not present in the roots config object, or whose value is '' or a non-string (number, null). Also occurs when the config defines the scope under a differently-cased or misspelled key.","commonSituations":"Typos in the scope name at the call site ('Project' vs 'project'); a fresh install where the config template only defines some scopes; an environment-specific config that omits a scope; a renamed scope constant not updated everywhere.","solutions":["Add the missing scope with a valid absolute directory path to the roots configuration.","Fix the scope name passed to the vault call so it matches a key defined in roots.","Verify the value is a non-empty string, not null/undefined/number.","Synchronize scope constants between caller code and the config file to prevent drift."],"exampleFix":"// before (config)\n{ project: '/vault/project' } // no 'personal' scope\nresolveMemoryRoot(roots, 'personal');\n\n// after\n{ project: '/vault/project', personal: '/vault/personal', [VAULT_ROOT_BOUNDARIES]: { project: '/vault/project', personal: '/vault/personal' } }","handlingStrategy":"validation","validationCode":"function assertScopeConfigured(roots, scope) {\n  const root = roots?.[scope];\n  if (typeof root !== 'string' || root.length === 0) {\n    throw new Error(`Scope \"${scope}\" has no memory root configured. Add it to your roots config.`);\n  }\n}","typeGuard":"const hasScopeRoot = (roots, scope) => typeof roots?.[scope] === 'string' && roots[scope].length > 0;","tryCatchPattern":"try {\n  const root = resolveMemoryRoot(roots, scope);\n} catch (err) {\n  if (err.message.startsWith('No memory root is configured')) {\n    throw new Error(`Unknown memory scope \"${scope}\". Configured scopes: ${Object.keys(roots).filter(k => k !== '__boundaries').join(', ')}`);\n  }\n  throw err;\n}","preventionTips":["Import scope names from shared constants instead of typing strings at call sites.","List all available scopes in config docs and error output.","Add a startup check that every scope used by the codebase exists in the config.","Watch for case/typo mismatches between call sites and config keys."],"tags":["configuration","memory-vault","missing-scope","missing-config-key"],"backgroundTag":"missing-config-key","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"}