{"record":{"id":"7edbbf2b3a13e96d","repo":"remoteintech/remote-jobs","slug":"missing-required-section-section","errorCode":null,"errorMessage":"Missing required section: \"## ${section}\"","messagePattern":"Missing required section: \"## (.+?)\"","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":".github/scripts/validate-companies.js","lineNumber":175,"sourceCode":"      `Invalid \\`website\\` URL: \"${data.website}\". Must be a full URL starting with https:// or http://`\n    );\n  }\n\n  if (data.careers_url && !isValidUrl(data.careers_url)) {\n    errors.push(\n      `Invalid \\`careers_url\\`: \"${data.careers_url}\". Must be a full URL starting with https:// or http://`\n    );\n  }\n\n  // Check required markdown sections\n  const bodyContent = content.replace(/^---[\\s\\S]*?---/, \"\");\n  for (const section of REQUIRED_SECTIONS) {\n    const sectionPattern = new RegExp(\n      `^##\\\\s+${escapeRegExp(section)}\\\\s*$`,\n      \"m\"\n    );\n    if (!sectionPattern.test(bodyContent)) {\n      errors.push(`Missing required section: \"## ${section}\"`);\n    }\n  }\n\n  // Check that \"Company blurb\" has content (not just the heading)\n  const blurbMatch = bodyContent.match(\n    /^##\\s+Company blurb\\s*\\n([\\s\\S]*?)(?=^##\\s|\\s*$)/m\n  );\n  if (blurbMatch && !blurbMatch[1].trim()) {\n    warnings.push(\n      'The \"Company blurb\" section is empty. Please add a description of the company.'\n    );\n  }\n\n  return { errors, warnings };\n}\n\nfunction isValidUrl(str) {\n  try {","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/remoteintech/remote-jobs/blob/b1dd8deb1945e5ff58f9e9c35e318f53c8871930/.github/scripts/validate-companies.js#L157-L193","documentation":"Required-section check at lines 167-177. After stripping the frontmatter block, each section in REQUIRED_SECTIONS = ['Company blurb', 'Remote status', 'How to apply'] is matched by the regex /^##\\s+<escaped section>\\s*$/m. The heading must be exactly a level-2 (`##`) heading whose only text is the section name — level-1, level-3, trailing colons, trailing text, or extra whitespace all fail.","triggerScenarios":"Section is absent; uses the wrong heading level (`#` or `###`); heading has trailing punctuation (`## Company blurb:`); heading has trailing whitespace stripped inconsistently; the body kept the heading inside a code fence so it isn't a real heading.","commonSituations":"Contributor unfamiliar with the template uses h1 for the title and h3 for subsections; markdown linter rewrites heading levels; autoformatter adds trailing colons.","solutions":["Add each missing section as `## <Section Name>` exactly, on its own line, level-2 only.","Confirm there is no trailing punctuation or whitespace after the heading text.","Re-run the validator to confirm the section passes."],"exampleFix":"// before\n# Company blurb\n\nAcme makes things.\n// after\n## Company blurb\n\nAcme makes things.","handlingStrategy":"validation","validationCode":"const REQUIRED_SECTIONS = ['Company blurb', 'Remote status', 'How to apply'];\nfunction missingSections(body) {\n  return REQUIRED_SECTIONS.filter(s =>\n    !new RegExp(`^##\\\\s+${escapeRegExp(s)}\\\\s*$`, 'm').test(body));\n}","typeGuard":"function hasRequiredSections(body) {\n  return REQUIRED_SECTIONS.every(s =>\n    new RegExp(`^##\\\\s+${escapeRegExp(s)}\\\\s*$`, 'm').test(body));\n}","tryCatchPattern":null,"preventionTips":["Use exactly level-2 (`##`) headings with the literal section names.","Don't append colons or extra words to the heading text.","Start from the canonical template so all three sections are present from the outset."],"tags":["markdown","sections","frontmatter","regex"],"backgroundTag":null,"analyzedSha":"b1dd8deb1945e5ff58f9e9c35e318f53c8871930","analyzedAt":"2026-08-13T04:09:00.804Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}