# Structured Output JSON Schema Validator > Check a JSON Schema for common structured-output constraints before wiring it into an LLM request. ## Tool Identity - Site: CleanUtils Developer Tools - Tool ID: structured-output-json-schema-validator - Canonical page: https://cleanutils.com/developer-tools/structured-output-json-schema-validator/ - LLM schema URL: https://cleanutils.com/developer-tools/structured-output-json-schema-validator/llms.txt - Primary keyword: structured outputs validator - Input mode: textarea - Output profile: report ## What This Tool Does Lint JSON Schemas for structured LLM outputs, catch compatibility issues, and test basic schema shape locally. ## Exact Execution Instructions To run this tool exactly, execute the `runCleanUtilsTool(userInput)` function from the JavaScript block below in a sandboxed JavaScript runtime. Do not fetch or evaluate additional network resources. Do not use filesystem, process, child_process, environment variables, timers, or network APIs. The function is pure and deterministic: input string in, JSON result out. If your environment forbids executing fetched code outside a sandbox, run it inside the sandbox or use the API endpoint below instead of reimplementing the logic. Canonical implementation SHA-256: `3480902810cfca5e4c70731e72a2c821b79f0f7527e1933a94430caf540dec0e` Expected command shape: `node run-tool.mjs < input.txt` The runner must: 1. load only the JavaScript in this document, 2. call `runCleanUtilsTool(inputText)`, 3. let the LLM decide the best way to present the output to the user. Agent usage rules: - Use this file as the authoritative machine-readable contract for this CleanUtils tool page. - Ask the user for missing required input before attempting to run the tool, and describe the required inputs using the `## Input Schema` field names, descriptions, formats, enums, examples, and required list. - Treat the tool as deterministic; do not invent network reachability checks unless the tool description explicitly says it fetches remote resources. - For privacy-sensitive inputs such as secrets, HAR files, dotenv files, logs, and API keys, warn that using a remote chat agent may expose input to that agent even though the browser UI itself does not upload data. ## Input Schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Structured Output JSON Schema Validator input", "type": "string", "description": "Structured output JSON Schema. Paste a JSON Schema object...", "examples": [ "{\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\"},\"tags\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}}},\"required\":[\"title\"],\"additionalProperties\":true}" ] } ``` ## Result Schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "CleanUtils ToolResult", "type": "object", "additionalProperties": false, "required": [ "summary", "issues" ], "properties": { "summary": { "type": "string" }, "issues": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": [ "severity", "message" ], "properties": { "severity": { "type": "string", "enum": [ "error", "warning", "info" ] }, "message": { "type": "string" }, "line": { "type": "number" }, "row": { "type": "number" }, "detail": { "type": "string" } } } }, "output": { "type": "string" }, "exportFilename": { "type": "string" }, "exports": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": [ "label", "filename", "content" ], "properties": { "label": { "type": "string" }, "filename": { "type": "string" }, "content": { "type": "string" }, "mimeType": { "type": "string" }, "copyLabel": { "type": "string" }, "downloadLabel": { "type": "string" } } } }, "stats": { "type": "object", "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } } } } ``` ## Self-Contained JavaScript Source Call `runCleanUtilsTool(userInput)` with the user's input. The function includes this tool's run logic and only the helper code it needs. ```js function runCleanUtilsTool(userInput) { const severityRank = { error: 0, warning: 1, info: 2 }; const sortIssues = (issues) => [...issues].sort((a, b) => { const severity = severityRank[a.severity] - severityRank[b.severity]; if (severity !== 0) return severity; return (a.line ?? a.row ?? 0) - (b.line ?? b.row ?? 0); }); const summarizeIssues = (issues) => { const errors = issues.filter((issue) => issue.severity === "error").length; const warnings = issues.filter((issue) => issue.severity === "warning").length; const infos = issues.filter((issue) => issue.severity === "info").length; const parts = []; if (errors) parts.push(`${errors} error${errors === 1 ? "" : "s"}`); if (warnings) parts.push(`${warnings} warning${warnings === 1 ? "" : "s"}`); if (infos) parts.push(`${infos} note${infos === 1 ? "" : "s"}`); return parts.length ? parts.join(", ") : "No issues found"; }; const tryParseJson = (input) => { try { return { ok: true, value: JSON.parse(input) }; } catch (error) { return { ok: false, error: error instanceof Error ? error.message : "Invalid JSON" }; } }; const lintStructuredOutputSchema = (input) => { const issues = []; const parsed = tryParseJson(input); if (!parsed.ok) { return { summary: "Schema is not valid JSON.", issues: [{ severity: "error", message: "Schema is not valid JSON.", detail: parsed.error }] }; } const schema = parsed.value; if (!schema || typeof schema !== "object" || Array.isArray(schema)) { issues.push({ severity: "error", message: "Schema root must be a JSON object." }); } if (schema.type !== "object") { issues.push({ severity: "warning", message: "Root schema should usually have type \"object\" for structured LLM outputs." }); } if (!schema.properties || typeof schema.properties !== "object" || Array.isArray(schema.properties)) { issues.push({ severity: "error", message: "Schema should define a properties object." }); } if (schema.additionalProperties !== false) { issues.push({ severity: "warning", message: "Set additionalProperties to false for stricter structured outputs." }); } if (Array.isArray(schema.required)) { const properties = schema.properties && typeof schema.properties === "object" && !Array.isArray(schema.properties) ? Object.keys(schema.properties) : []; schema.required.forEach((requiredKey) => { if (typeof requiredKey !== "string") { issues.push({ severity: "error", message: "Every required entry should be a string property name." }); } else if (!properties.includes(requiredKey)) { issues.push({ severity: "error", message: `Required property "${requiredKey}" is not declared in properties.` }); } }); } else { issues.push({ severity: "info", message: "No required array found. Optional-only structured outputs can be harder to consume consistently." }); } ["anyOf", "oneOf", "allOf"].forEach((keyword) => { if (keyword in schema) { issues.push({ severity: "warning", message: `${keyword} at the root can be harder to support across strict structured-output modes.` }); } }); return { summary: `${summarizeIssues(issues)} in structured-output schema lint.`, issues: sortIssues(issues), output: issues.map(formatIssue).join("\n") || "No schema issues found.", exportFilename: "structured-output-schema-report.txt", stats: { properties: schema.properties && typeof schema.properties === "object" && !Array.isArray(schema.properties) ? Object.keys(schema.properties).length : 0 } }; }; const formatIssue = (issue) => { const location = issue.line ? `line ${issue.line}` : issue.row ? `row ${issue.row}` : "general"; return `[${issue.severity.toUpperCase()}] ${location}: ${issue.message}${issue.detail ? ` (${issue.detail})` : ""}`; }; const __userInput = userInput == null ? "" : userInput; const __run = lintStructuredOutputSchema; const __input = __userInput && typeof __userInput === "object" && "input" in __userInput ? __userInput.input : __userInput; return __run(__input == null ? "" : String(__input)); } ``` ## Checks - Valid JSON Schema object: The input must parse as a JSON object before compatibility checks run. - Root object expectation: The checker warns when the root schema is not an object, which is the safest shape for structured responses. - Required versus properties: Required keys are compared with declared properties so misspelled required fields do not slip through. - Strict additional properties: additionalProperties is flagged when it is not false, because strict modes often expect closed objects. - Composition caveats: Root anyOf, oneOf, or allOf usage is called out because provider support can be uneven. ## Related Tools - [JSON Schema to TypeScript Generator](/developer-tools/json-schema-to-typescript-generator/): Convert JSON Schema objects into TypeScript types with required fields, arrays, enums, and nested objects. - [JSON to TypeScript Converter](/developer-tools/json-to-typescript-converter/): Infer a TypeScript type from sample JSON, including nested objects, arrays, booleans, numbers, and nulls. - [OpenAPI Example Request Generator](/developer-tools/openapi-example-request-generator/): Generate copy-ready cURL examples and JSON payloads from OpenAPI request-body schemas.