{"record":{"id":"9ef9bd6bf3753997","repo":"deepseek-ai/deepseek-harness","slug":"tool-result-must-be-losslessly-json-serializable","errorCode":null,"errorMessage":"tool result must be losslessly JSON-serializable","messagePattern":"tool result must be losslessly JSON-serializable","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/core/tools/src/index.ts","lineNumber":636,"sourceCode":"    // coercion. Error normalization is the outermost safety boundary, so its\n    // fallback must itself be total.\n    return '<unprintable thrown value>'\n  }\n}\n\n/** Derive one failure message from policy feedback without changing its rendered blocks. */\nfunction failureMessageFromContent(content: ContentBlock[]): string {\n  const text = content\n    .map(block => block.type === 'text' ? block.text : `[${block.type} content]`)\n    .join('\\n')\n  return text.length > 0 ? text : 'tool result blocked by post-execute policy'\n}\n\n/** Snapshot and freeze one durable tool-result projection or reject lossy data. */\nfunction materializePresentation<T>(candidate: T): T {\n  const detached = snapshotJsonValue(candidate)\n  if (detached === undefined) {\n    throw new TypeError('tool result must be losslessly JSON-serializable')\n  }\n  return deepFreeze(detached)\n}\n\n/** Structured `{ name, code }` for a thrown HarnessError, else undefined. */\nfunction errorInfo(error: unknown): ToolErrorInfo | undefined {\n  try {\n    return error instanceof HarnessError ? { name: error.name, code: error.code } : undefined\n  } catch {\n    return undefined\n  }\n}\n\n/** How the registry presents its tools to the model (see {@link Config.mode}). */\nexport type ToolPresentationMode = 'native' | 'code' | 'both'\n\n/** Plugin config: how the registered tools are presented to the model. */\nexport interface Config {","sourceCodeStart":618,"sourceCodeEnd":654,"githubUrl":"https://github.com/deepseek-ai/deepseek-harness/blob/b150a551b8d465e31e418e1b2eaf5e79bbb7d28e/packages/core/tools/src/index.ts#L618-L654","documentation":"Durable-boundary rejection in the tool-result snapshot path: a tool result value does not survive lossless JSON serialization (e.g. contains undefined, functions, bigint, symbols, or class instances). The result must be frozen into a JSON-exact projection before it is persisted or shown, so non-representable values are rejected rather than silently mangled.","triggerScenarios":"Thrown at packages/core/tools/src/index.ts:636 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Return a plain JSON value (objects, arrays, strings, numbers, booleans, null) from the tool","Convert Date/Map/Set/class instances to plain JSON structures before returning","Drop function or symbol-valued properties from the result"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"b150a551b8d465e31e418e1b2eaf5e79bbb7d28e","analyzedAt":"2026-08-24T18:12:29.105Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}