different-ai/openwork · error · ProbeFailure

CONFIGURATION

CONFIGURATION

Error message

Probe timeout must be an integer from 50 through 120000 milliseconds

What it means

probeEnterpriseMcpMockServer validates options.timeoutMs before starting any probe phases. The probe is a bounded, deadline-driven diagnostic (each phase shares one overall deadline), so it refuses timeouts that are not integers or that fall outside 50-120000 ms; otherwise phases could either fire instantly or hang unreasonably. It throws a ProbeFailure with phase CONFIGURATION before any network activity.

Source

Thrown at packages/enterprise-mcp-mock-server/src/testing/probe.ts:419

  }
  if (code === "PROVIDER_DUPLICATE_REQUEST") {
    return new ProbeFailure("PROVIDER_EXECUTION", "provider_duplicate_request", "The gateway amplified one MCP tool call into duplicate requests")
  }
  return new ProbeFailure("MCP_TOOL_EXECUTION", "mcp_tool", `Provider returned tool error '${code}'`)
}

export async function probeEnterpriseMcpMockServer(options: ProbeEnterpriseMcpMockServerOptions): Promise<ProbeResult> {
  const diagnosticId = randomUUID()
  const scenario = scenarioSchema.parse(options.scenario)
  const profile = getProviderProfile(scenario.profileId)
  const activeFault = scenario.activeFault ? getFaultDefinition(scenario.activeFault.id) : undefined
  const mode = options.mode ?? "fixture-conformance"
  const baseUrl = new URL(options.baseUrl)
  assertLocalProbeBase(baseUrl)
  const mcpUrl = new URL(profile.endpointPath, baseUrl).href
  const timeoutMs = options.timeoutMs ?? 30_000
  if (!Number.isInteger(timeoutMs) || timeoutMs < 50 || timeoutMs > 120_000) {
    throw new ProbeFailure("CONFIGURATION", "configuration", "Probe timeout must be an integer from 50 through 120000 milliseconds")
  }
  const overallDeadline = Date.now() + timeoutMs
  const phases: ProbePhaseResult[] = []
  const mutable: MutableProbeState = { negotiatedProtocolVersion: null, toolCount: 0 }
  const sensitiveValues = [options.credentials?.clientSecret ?? ""]
  let sessionId = ""
  let accessToken = ""
  let refreshToken = ""
  let revocationClientId = scenario.oauth.clientId
  let revocationClientSecret = options.credentials?.clientSecret ?? ""
  let negotiatedProtocolHeader = ""
  let revocationEndpoint: URL | null = null
  const cleanup = async (requireValidDelete: boolean): Promise<void> => {
    const cleanupDeadline = Date.now() + 2_000
    if (sessionId && accessToken && negotiatedProtocolHeader) {
      try {
        const deleteResponse = await fetchStep(mcpUrl, {
          method: "DELETE",

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Pass an integer timeoutMs between 50 and 120000, e.g. timeoutMs: 30000.
  2. If deriving from seconds, round: Math.round(seconds * 1000).
  3. Omit timeoutMs entirely to use the 30-second default.
  4. Clamp user/config input before calling: Math.min(120000, Math.max(50, value)) and check Number.isInteger.

Example fix

// before
await probeEnterpriseMcpMockServer({ baseUrl, timeoutMs: 0.5 * 60_000 + 0.4 })
// after
await probeEnterpriseMcpMockServer({ baseUrl, timeoutMs: Math.round(0.5 * 60_000) })
Defensive patterns

Strategy: validation

Validate before calling

const timeoutMs = options.timeoutMs ?? 30_000
if (!Number.isInteger(timeoutMs) || timeoutMs < 50 || timeoutMs > 120_000) {
  throw new RangeError(`timeoutMs must be an integer from 50 through 120000, got ${timeoutMs}`)
}
await probeEnterpriseMcpMockServer({ ...options, timeoutMs })

Type guard

function isValidProbeTimeout(v: unknown): v is number {
  return typeof v === "number" && Number.isInteger(v) && v >= 50 && v <= 120_000
}

Try / catch

try {
  await probeEnterpriseMcpMockServer({ baseUrl, timeoutMs: 30_000 })
} catch (e) {
  if (e instanceof ProbeFailure && e.phase === "CONFIGURATION") {
    console.error("Bad probe options:", e.message)
  } else throw e
}

Prevention

When it happens

Trigger: Calling probeEnterpriseMcpMockServer with timeoutMs set to a non-integer (e.g. 1500.5), below 50 (e.g. 10), above 120000 (e.g. 300000), or a NaN value passed from computed/config input.

Common situations: Multiplying seconds by 1000 with a fractional seconds value, loading the timeout from an env var or JSON config as a string-ish/float value, or setting an 'unlimited' style large value like Number.MAX_SAFE_INTEGER or 600000 to 'wait forever'.

Understand the failure class

Related errors


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/07736a92285fbe2c. Report an issue: GitHub.