{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":[]},"type":"markdown"},"seo":{"title":"Custom Validation Hook Context","llmstxt":{"hide":false,"sections":[{"title":"Table of contents","includeFiles":["**/*"],"excludeFiles":[]}],"excludeFiles":[]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"custom-validation-hook-context","__idx":0},"children":["Custom Validation Hook Context"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This document describes the objects, data structures, and utilities available to you when writing custom pre-validation and post-validation hooks. Use this reference to implement custom business logic that executes during the content ingestion process."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Hooks run in a secure, sandboxed JavaScript environment. When your hook executes, the system injects specific objects into the global scope, allowing you to inspect the data package, review job metadata, and report validation results."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"prerequisites","__idx":1},"children":["Prerequisites"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Before writing custom hooks, ensure you are familiar with:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["JavaScript (ES5/ES6):"]}," Hooks are written in standard JavaScript."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Data Import Format:"]}," Understanding the structure of articles, folders, and topics as defined in the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/developer-portal/guides/ingestion/data-import-format-guide"},"children":["Format Guide"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Hook Architecture:"]}," Whether you are writing a ",{"$$mdtype":"Tag","name":"em","attributes":{},"children":["Pre-Validation"]}," hook (runs before standard checks) or a ",{"$$mdtype":"Tag","name":"em","attributes":{},"children":["Post-Validation"]}," hook (runs after standard checks)."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"security-and-environment-restrictions","__idx":2},"children":["Security and Environment Restrictions"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Your code executes in a restricted sandbox. For security reasons, the following capabilities are ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["NOT available"]},":"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["File system access (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["fs"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["__dirname"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["__filename"]},")"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Network access (HTTP requests)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Module loading (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["require"]},")"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Global process access (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["process"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["global"]},")"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["eval()"]}," or dynamic code execution"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Allowed Capabilities:"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Accessing injected objects (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["data"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["metadata"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["validationResults"]},")"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Using the provided ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["helpers"]}," library"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Using ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["console.log()"]}," for system logging"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Standard JavaScript logic (loops, conditionals, array manipulation)"]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"available-objects","__idx":3},"children":["Available Objects"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The following objects are injected into your hook's scope at runtime."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"1-data---package-content","__idx":4},"children":["1. ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["data"]}," - Package Content"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["data"]}," object represents the parsed content from the package being imported. You can inspect this object to validate naming conventions, folder structures, or content requirements."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Structure Overview:"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","header":{"controls":{"copy":{}}},"source":"data = {\n  articles: [],        // Array of article objects\n  folders: [],         // Array of folder objects\n  portals: [],         // Array of portal objects\n  topics: [],          // Array of topic objects\n  macros: []           // Array of macro objects\n}\n","lang":"javascript"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Article Object Model:"]}," ","Each item in the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["articles"]}," array contains the following properties:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","header":{"controls":{"copy":{}}},"source":"{\n  name: \"article-name\",                     // Required: Article name\n  folder: {\n    path: \"Articles/Content/Shared\"         // Required: Full folder path\n  },\n  content: \"content/article.html\",          // Path to file OR direct HTML string\n  ai: \"true\",                               // String \"true\"/\"false\"\n  availabilityDate: \"2025-01-28T19:53:58Z\", // Optional\n  metadata: {                              \n    description: \"Sample Article\",\n    keywords: \"Chat\",\n    additionalInfo: \"Info\"\n  },\n  articleMacro: {                           // Present only if article is a Macro\n    name: \"CompanySize\",\n    defaultValue: \"<p>[default]</p>\"\n  },\n  customAttributes: [\n    { name: \"attribute1\", value: \"value1\" }\n  ],\n  // ... various optional fields (classifications, relatedArticles, etc.)\n}\n","lang":"javascript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"2-metadata---job-context","__idx":5},"children":["2. ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["metadata"]}," - Job Context"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["metadata"]}," object provides context about the current execution environment and the job itself."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Structure:"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","header":{"controls":{"copy":{}}},"source":"metadata = {\n  packageId: \"package-123\",    // Unique Job ID\n  domain: \"example.com\",       // Tenant Domain\n  tenantId: \"tenant-456\",      // Tenant ID\n  departmentName: \"Support\"    // (Import workflow only)\n}\n","lang":"javascript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"3-validationresults---standard-validation-output","__idx":6},"children":["3. ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["validationResults"]}," - Standard Validation Output"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Note:"]}," This object is available ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["ONLY"]}," in Post-Validation hooks."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This object contains the results of the standard system validation that ran immediately before your hook. You can use this to determine if you should block an import based on specific errors."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Structure:"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","header":{"controls":{"copy":{}}},"source":"validationResults = {\n  success: false,\n  summary: {\n    totalArticles: 100,\n    totalErrors: 7,\n    invalidAttachments: 5\n  },\n  errors: [\n    {\n      type: \"attachment_missing\",\n      articleName: \"article-1\",\n      message: \"Attachment 'image.png' not found\",\n      fix: \"Ensure attachment exists in resources folder\"\n    }\n  ],\n  warnings: [] \n}\n","lang":"javascript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"4-helpers---utility-library","__idx":7},"children":["4. ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["helpers"]}," - Utility Library"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["helpers"]}," object provides safe utility functions to handle data checking without throwing runtime errors on undefined properties."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Available Functions:"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["helpers.hasField(obj, field)"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"em","attributes":{},"children":["Returns:"]}," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["boolean"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"em","attributes":{},"children":["Usage:"]}," Checks if an object has a specific property."]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["helpers.isNotEmpty(value)"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"em","attributes":{},"children":["Returns:"]}," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["boolean"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"em","attributes":{},"children":["Usage:"]}," Checks if a value is not null, undefined, empty string, empty array, or empty object."]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["helpers.isEmpty(value)"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"em","attributes":{},"children":["Returns:"]}," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["boolean"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"em","attributes":{},"children":["Usage:"]}," The inverse of ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["isNotEmpty"]},"."]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["helpers.isArray(value)"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"em","attributes":{},"children":["Returns:"]}," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["boolean"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"em","attributes":{},"children":["Usage:"]}," Validates if a value is an array."]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["helpers.isString(value)"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"em","attributes":{},"children":["Returns:"]}," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["boolean"]}]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["helpers.isNumber(value)"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"em","attributes":{},"children":["Returns:"]}," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["boolean"]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"5-console---logging","__idx":8},"children":["5. ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["console"]}," - Logging"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["console.log()"]}," to write messages to the system logs. This is essential for debugging hooks or logging specific validation decisions."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","header":{"controls":{"copy":{}}},"source":"console.log('Processing package:', metadata.packageId);\nconsole.log('Found error in article:', article.name);\n","lang":"javascript"},"children":[]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"execution-contexts","__idx":9},"children":["Execution Contexts"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Depending on when your hook runs, different objects are available."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"pre-validation-hooks","__idx":10},"children":["Pre-Validation Hooks"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["When:"]}," Executes ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["BEFORE"]}," the standard system validation."," ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Goal:"]}," Enforce custom business rules (e.g., \"All articles must have a keyword\" or \"AI must be enabled\")."]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["✅ ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["data"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["✅ ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["metadata"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["✅ ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["helpers"]}," / ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["console"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["❌ ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["validationResults"]}," (Not available yet)"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"post-validation-hooks","__idx":11},"children":["Post-Validation Hooks"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["When:"]}," Executes ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["AFTER"]}," the standard system validation."," ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Goal:"]}," Review system errors and decide if the job should proceed (e.g., \"Fail the job if any image attachments are missing\")."]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["✅ ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["data"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["✅ ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["metadata"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["✅ ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["validationResults"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["✅ ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["helpers"]}," / ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["console"]}]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"return-value-format","__idx":12},"children":["Return Value Format"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Your hook ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["must"]}," return a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["result"]}," object. This object dictates whether the validation process considers the job a success or failure."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"success-scenario","__idx":13},"children":["Success Scenario"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Return this to allow the job to proceed."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","header":{"controls":{"copy":{}}},"source":"var result = {\n  success: true,\n  message: \"Custom validation passed.\"\n};\nreturn result;\n","lang":"javascript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"failure-scenario","__idx":14},"children":["Failure Scenario"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Return this to stop the job and report an error to the user."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","header":{"controls":{"copy":{}}},"source":"var result = {\n  success: false,\n  error: \"Critical Business Rule Failed: Articles must have an author.\",\n  details: {\n    failedCount: 5,\n    articleNames: [\"intro\", \"setup\", \"config\"]\n  }\n};\nreturn result;\n","lang":"javascript"},"children":[]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"example-pre-validation-logic","__idx":15},"children":["Example: Pre-Validation Logic"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This example demonstrates checking that every article contains a specific metadata field."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","header":{"controls":{"copy":{}}},"source":"// Initialize result\nvar result = { success: true };\n\n// Verify data exists\nif (helpers.hasField(data, 'articles') && helpers.isNotEmpty(data.articles)) {\n  \n  var invalidArticles = [];\n  \n  // Loop through articles\n  for (var i = 0; i < data.articles.length; i++) {\n    var article = data.articles[i];\n    \n    // Check for \"name\" field\n    if (!helpers.hasField(article, 'name')) {\n      invalidArticles.push({ index: i, issue: \"Missing name\" });\n      continue;\n    }\n\n    // Custom Rule: Check if 'description' exists in metadata\n    if (!helpers.hasField(article, 'metadata') || \n        !helpers.hasField(article.metadata, 'description') || \n        helpers.isEmpty(article.metadata.description)) {\n          \n      invalidArticles.push({ \n        name: article.name, \n        issue: \"Missing required description metadata\" \n      });\n    }\n  }\n  \n  // If we found issues, fail the job\n  if (invalidArticles.length > 0) {\n    result = {\n      success: false,\n      error: 'Articles failed custom metadata validation',\n      details: {\n        count: invalidArticles.length,\n        errors: invalidArticles\n      }\n    };\n  }\n}\n\n// Return the result object\nresult;\n","lang":"javascript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"example-post-validation-logic","__idx":16},"children":["Example: Post-Validation Logic"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This example checks the standard validation results. If there are standard errors, it logs them and fails the job explicitly."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","header":{"controls":{"copy":{}}},"source":"var result = { success: true };\n\n// Check if standard validation found errors\nif (helpers.hasField(validationResults, 'errors') && validationResults.errors.length > 0) {\n  \n  var errorCount = validationResults.errors.length;\n  console.log('Standard validation found ' + errorCount + ' errors.');\n\n  // Create a summary of error types\n  var errorTypes = {};\n  validationResults.errors.forEach(function(err) {\n    var type = err.type || 'unknown';\n    errorTypes[type] = (errorTypes[type] || 0) + 1;\n  });\n\n  // Fail the job\n  result = {\n    success: false,\n    error: 'Standard validation failed with ' + errorCount + ' errors.',\n    details: {\n      summary: errorTypes,\n      firstError: validationResults.errors[0].message\n    }\n  };\n}\n\nresult;\n","lang":"javascript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"best-practices","__idx":17},"children":["Best Practices"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Defensive Coding:"]}," Always use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["helpers.hasField()"]}," before accessing nested properties. For example, do not access ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["article.metadata.description"]}," directly without checking if ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["article.metadata"]}," exists first."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Clear Error Messages:"]}," When returning ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["success: false"]},", provide a descriptive ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error"]}," string and use the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["details"]}," object to pass relevant data (like lists of failed article names)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Logging:"]}," Use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["console.log"]}," generously. These logs are saved with the job history and are vital for troubleshooting why a hook failed a package."]}]}]},"headings":[{"value":"Custom Validation Hook Context","id":"custom-validation-hook-context","depth":1},{"value":"Prerequisites","id":"prerequisites","depth":2},{"value":"Security and Environment Restrictions","id":"security-and-environment-restrictions","depth":2},{"value":"Available Objects","id":"available-objects","depth":2},{"value":"1. data - Package Content","id":"1-data---package-content","depth":3},{"value":"2. metadata - Job Context","id":"2-metadata---job-context","depth":3},{"value":"3. validationResults - Standard Validation Output","id":"3-validationresults---standard-validation-output","depth":3},{"value":"4. helpers - Utility Library","id":"4-helpers---utility-library","depth":3},{"value":"5. console - Logging","id":"5-console---logging","depth":3},{"value":"Execution Contexts","id":"execution-contexts","depth":2},{"value":"Pre-Validation Hooks","id":"pre-validation-hooks","depth":3},{"value":"Post-Validation Hooks","id":"post-validation-hooks","depth":3},{"value":"Return Value Format","id":"return-value-format","depth":2},{"value":"Success Scenario","id":"success-scenario","depth":3},{"value":"Failure Scenario","id":"failure-scenario","depth":3},{"value":"Example: Pre-Validation Logic","id":"example-pre-validation-logic","depth":2},{"value":"Example: Post-Validation Logic","id":"example-post-validation-logic","depth":2},{"value":"Best Practices","id":"best-practices","depth":2}],"frontmatter":{"seo":{"title":"Custom Validation Hook Context"}},"lastModified":"2026-04-23T22:46:33.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/developer-portal/guides/ingestion/validation-hook-guide","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}