{"record":{"id":"6ffe5c70b4363533","repo":"hoppscotch/hoppscotch","slug":"hoppscotch-reservedconflict-is-reserved-by","errorCode":null,"errorMessage":"[Hoppscotch] '${reservedConflict}' is reserved by Hoppscotch's script wrapper and cannot be used as an import binding. Please rename the import.","messagePattern":"\\[Hoppscotch\\] '(.+?)' is reserved by Hoppscotch's script wrapper and cannot be used as an import binding\\. Please rename the import\\.","errorType":"exception","errorClass":"SyntaxError","httpStatus":null,"severity":"error","filePath":"packages/hoppscotch-js-sandbox/src/utils/scripting.ts","lineNumber":241,"sourceCode":"  if (fns.length === 0 && allImports.length === 0 && !parseError) return \"\"\n\n  // Errors short-circuit before synthesis; reserved-name check sits before\n  // the import-only return so reserved bindings still surface.\n  if (parseError !== undefined) {\n    return synthesizeReporterWrapper(\n      `throw new SyntaxError(${JSON.stringify(`[Hoppscotch] Script failed to parse: ${parseError}`)});`\n    )\n  }\n\n  if (conflictingName !== undefined) {\n    return synthesizeReporterWrapper(\n      `throw new SyntaxError(${JSON.stringify(`[Hoppscotch] '${conflictingName}' is imported from different sources across scripts in this request's chain. Please import it from a single source, or rename one of the imports to resolve the conflict.`)});`\n    )\n  }\n\n  if (reservedConflict !== undefined) {\n    return synthesizeReporterWrapper(\n      `throw new SyntaxError(${JSON.stringify(`[Hoppscotch] '${reservedConflict}' is reserved by Hoppscotch's script wrapper and cannot be used as an import binding. Please rename the import.`)});`\n    )\n  }\n\n  // Import-only cascade: skip the try/catch — no awaited bodies to route\n  // errors from. Module-evaluation errors propagate via faraday-cage.\n  if (fns.length === 0) return allImports.join(\"\\n\")\n\n  // Wrap the awaited chain in try/catch so top-level throws / rejected\n  // awaits reach the host reporter; faraday-cage otherwise swallows\n  // async-boundary errors via its keepAlive loop.\n  const body = fns.map((fn) => `await (${fn})();`).join(\"\\n\")\n  const tryBlock = synthesizeReporterWrapper(body)\n\n  if (allImports.length === 0) return tryBlock\n\n  return [allImports.join(\"\\n\"), tryBlock].join(\"\\n\")\n}\n","sourceCodeStart":223,"sourceCodeEnd":259,"githubUrl":"https://github.com/hoppscotch/hoppscotch/blob/1acb8a3a7581e4db32ba0d529170c4669a2e1053/packages/hoppscotch-js-sandbox/src/utils/scripting.ts#L223-L259","documentation":"Thrown during script combination when an import binding name collides with a name reserved by Hoppscotch's script wrapper internals. The reserved set is { '__hoppReporter', 'globalThis' } — the former is the reporter function injected by the wrapper to surface test results to the host, and the latter is read for the reporter at module scope. Importing these would cause a duplicate-declaration or shadowing error post-hoist, so the pre-cage check catches it early.","triggerScenarios":"A script contains `import { __hoppReporter } from 'somelib'` or `import { globalThis } from 'somelib'`. The binding name matches one of the two reserved identifiers, triggering this error before the script reaches the sandbox evaluator.","commonSituations":"A library happens to export a member named 'globalThis' (unlikely but possible with JS interop shims), or a user manually names an import '__hoppReporter' (e.g., copying internal Hoppscotch source code into a test script). This is rare in practice but the guard prevents a confusing post-hoist SyntaxError.","solutions":["Rename the import binding using `as`: `import { __hoppReporter as myReporter } from 'somelib'`.","If you imported globalThis, use a namespace import instead: `import * as gt from 'somelib'`.","Avoid copying Hoppscotch internal symbols into user scripts — they are not part of the public API."],"exampleFix":"// before\nimport { globalThis } from './shim'\n\n// after — rename the binding\nimport { globalThis as gtShim } from './shim'","handlingStrategy":"type-guard","validationCode":"// Check if any import binding collides with reserved names\nconst RESERVED = new Set(['__hoppReporter', 'globalThis'])\n\nfunction findReservedConflicts(scripts) {\n  const importRegex = /import\\s+(?:\\{([^}]+)\\}|(\\w+))(?:\\s*,\\s*\\{([^}]+)\\})?\\s+from/g\n  const conflicts = []\n  for (const script of scripts) {\n    let match\n    while ((match = importRegex.exec(script)) !== null) {\n      const names = (match[1] || match[3] || '')\n        .split(',')\n        .map(s => s.trim().split(' as ')[0].trim())\n        .filter(Boolean)\n      if (match[2]) names.push(match[2])\n      for (const name of names) {\n        if (RESERVED.has(name)) conflicts.push(name)\n      }\n    }\n  }\n  return conflicts\n}\n\nconst conflicts = findReservedConflicts(scripts)\nif (conflicts.length > 0) {\n  console.error('Reserved name conflicts:', conflicts)\n}","typeGuard":"const RESERVED_WRAPPER_NAMES = new Set(['__hoppReporter', 'globalThis'])\n\nfunction isReservedImportName(name) {\n  return RESERVED_WRAPPER_NAMES.has(name)\n}","tryCatchPattern":"// The SyntaxError is thrown inside the sandbox and surfaced via the host reporter\ntry {\n  const results = await runSandboxScripts(scripts)\n  const reservedError = results.errors?.find(e => e.message.includes('reserved by Hoppscotch'))\n  if (reservedError) {\n    console.error(reservedError.message)\n    // Rename the binding in the offending script\n  }\n} catch (e) {\n  console.error('Script error:', e.message)\n}","preventionTips":["Never name an import binding __hoppReporter or globalThis.","If a library exports these names, rename with `as` at the import site.","Avoid copying Hoppscotch internal source into user scripts.","Use namespace imports to avoid any name-level collision with internals."],"tags":["scripting","reserved-name","import-conflict","sandbox"],"backgroundTag":null,"analyzedSha":"1acb8a3a7581e4db32ba0d529170c4669a2e1053","analyzedAt":"2026-08-12T11:34:52.648Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}