{"record":{"id":"153dd4fdd1666eb8","repo":"paperclipai/paperclip","slug":"unsupported-expose-field-s-unknownkeys-sort","errorCode":null,"errorMessage":"Unsupported expose field(s): ${unknownKeys.sort().join(\", \")}","messagePattern":"Unsupported expose field\\(s\\): (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/shared/src/validators/runtime-exposure.ts","lineNumber":154,"sourceCode":"}\n\n/**\n * Resolve the exposure config a service *declared* (as opposed to the one it\n * inherits by default). Returns null unless the block explicitly opts in.\n *\n * Recognized sub-fields fall back to {@link DEFAULT_TAILSCALE_HTTPS_EXPOSURE},\n * so `{ type: \"tailscale_https\" }` is a complete declaration; unknown keys still\n * throw rather than being silently dropped.\n */\nexport function resolveDeclaredRuntimeExposureConfig(\n  value: unknown,\n): RuntimeExposureConfigInput | null {\n  if (readRuntimeExposureIntent(value) !== \"enabled\") return null;\n  const expose = value as Record<string, unknown>;\n  const known = new Set<string>([...RUNTIME_EXPOSURE_CONFIG_KEYS, ...RUNTIME_EXPOSURE_TRANSPORT_KEYS]);\n  const unknownKeys = Object.keys(expose).filter((key) => !known.has(key));\n  if (unknownKeys.length > 0) {\n    throw new Error(`Unsupported expose field(s): ${unknownKeys.sort().join(\", \")}`);\n  }\n  const merged: Record<string, unknown> = { ...DEFAULT_TAILSCALE_HTTPS_EXPOSURE };\n  for (const key of RUNTIME_EXPOSURE_CONFIG_KEYS) {\n    if (expose[key] !== undefined) merged[key] = expose[key];\n  }\n  // `tailscaleHttps: true` is shorthand for the provider; normalize it away.\n  merged.type = \"tailscale_https\";\n  return runtimeExposureConfigSchema.parse(merged);\n}\n","sourceCodeStart":136,"sourceCodeEnd":164,"githubUrl":"https://github.com/paperclipai/paperclip/blob/120ae5428fa29bee300bcf806491cd4d965fbb7c/packages/shared/src/validators/runtime-exposure.ts#L136-L164","documentation":"Strict-schema guard in resolveDeclaredRuntimeExposureConfig: the exposure block's declared type is recognized, but it contains keys outside the known sub-fields. Unknown keys throw (rather than being silently dropped) so typos like 'hosts' vs 'host' surface immediately; the sorted key list names exactly which fields were unrecognized.","triggerScenarios":"Thrown at packages/shared/src/validators/runtime-exposure.ts:154 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Remove the unsupported fields from the expose config; use only documented keys."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"120ae5428fa29bee300bcf806491cd4d965fbb7c","analyzedAt":"2026-08-18T22:49:45.177Z","contentChangedAt":"2026-08-18T22:49:45.177Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}