hoppscotch/hoppscotch · error · SyntaxError

[Hoppscotch] '${reservedConflict}' is reserved by Hoppscotch

Error message

[Hoppscotch] '${reservedConflict}' is reserved by Hoppscotch's script wrapper and cannot be used as an import binding. Please rename the import.

What it means

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.

Source

Thrown at packages/hoppscotch-js-sandbox/src/utils/scripting.ts:241

  if (fns.length === 0 && allImports.length === 0 && !parseError) return ""

  // Errors short-circuit before synthesis; reserved-name check sits before
  // the import-only return so reserved bindings still surface.
  if (parseError !== undefined) {
    return synthesizeReporterWrapper(
      `throw new SyntaxError(${JSON.stringify(`[Hoppscotch] Script failed to parse: ${parseError}`)});`
    )
  }

  if (conflictingName !== undefined) {
    return synthesizeReporterWrapper(
      `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.`)});`
    )
  }

  if (reservedConflict !== undefined) {
    return synthesizeReporterWrapper(
      `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.`)});`
    )
  }

  // Import-only cascade: skip the try/catch — no awaited bodies to route
  // errors from. Module-evaluation errors propagate via faraday-cage.
  if (fns.length === 0) return allImports.join("\n")

  // Wrap the awaited chain in try/catch so top-level throws / rejected
  // awaits reach the host reporter; faraday-cage otherwise swallows
  // async-boundary errors via its keepAlive loop.
  const body = fns.map((fn) => `await (${fn})();`).join("\n")
  const tryBlock = synthesizeReporterWrapper(body)

  if (allImports.length === 0) return tryBlock

  return [allImports.join("\n"), tryBlock].join("\n")
}

View on GitHub (pinned to 1acb8a3a75)

Solutions

  1. Rename the import binding using `as`: `import { __hoppReporter as myReporter } from 'somelib'`.
  2. If you imported globalThis, use a namespace import instead: `import * as gt from 'somelib'`.
  3. Avoid copying Hoppscotch internal symbols into user scripts — they are not part of the public API.

Example fix

// before
import { globalThis } from './shim'

// after — rename the binding
import { globalThis as gtShim } from './shim'
Defensive patterns

Strategy: type-guard

Validate before calling

// Check if any import binding collides with reserved names
const RESERVED = new Set(['__hoppReporter', 'globalThis'])

function findReservedConflicts(scripts) {
  const importRegex = /import\s+(?:\{([^}]+)\}|(\w+))(?:\s*,\s*\{([^}]+)\})?\s+from/g
  const conflicts = []
  for (const script of scripts) {
    let match
    while ((match = importRegex.exec(script)) !== null) {
      const names = (match[1] || match[3] || '')
        .split(',')
        .map(s => s.trim().split(' as ')[0].trim())
        .filter(Boolean)
      if (match[2]) names.push(match[2])
      for (const name of names) {
        if (RESERVED.has(name)) conflicts.push(name)
      }
    }
  }
  return conflicts
}

const conflicts = findReservedConflicts(scripts)
if (conflicts.length > 0) {
  console.error('Reserved name conflicts:', conflicts)
}

Type guard

const RESERVED_WRAPPER_NAMES = new Set(['__hoppReporter', 'globalThis'])

function isReservedImportName(name) {
  return RESERVED_WRAPPER_NAMES.has(name)
}

Try / catch

// The SyntaxError is thrown inside the sandbox and surfaced via the host reporter
try {
  const results = await runSandboxScripts(scripts)
  const reservedError = results.errors?.find(e => e.message.includes('reserved by Hoppscotch'))
  if (reservedError) {
    console.error(reservedError.message)
    // Rename the binding in the offending script
  }
} catch (e) {
  console.error('Script error:', e.message)
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of hoppscotch/hoppscotch@1acb8a3a75 (2026-08-12). Data as JSON: /api/errors/6ffe5c70b4363533. Report an issue: GitHub.