{"record":{"id":"e43c4c99eee067a7","repo":"remoteintech/remote-jobs","slug":"invalid-technology-tag-tech-valid-tags-v","errorCode":null,"errorMessage":"Invalid technology tag: \"${tech}\". Valid tags: ${VALID_TECHNOLOGIES.join(\", \")}","messagePattern":"Invalid technology tag: \"(.+?)\"\\. Valid tags: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":".github/scripts/validate-companies.js","lineNumber":138,"sourceCode":"\n  if (data.remote_policy && !VALID_REMOTE_POLICIES.includes(data.remote_policy)) {\n    errors.push(\n      `Invalid \\`remote_policy\\`: \"${data.remote_policy}\". Must be one of: ${VALID_REMOTE_POLICIES.join(\", \")}`\n    );\n  }\n\n  if (data.company_size && !VALID_COMPANY_SIZES.includes(data.company_size)) {\n    errors.push(\n      `Invalid \\`company_size\\`: \"${data.company_size}\". Must be one of: ${VALID_COMPANY_SIZES.join(\", \")}`\n    );\n  }\n\n  // Validate technologies array\n  if (data.technologies && Array.isArray(data.technologies)) {\n    for (const tech of data.technologies) {\n      if (!VALID_TECHNOLOGIES.includes(tech)) {\n        errors.push(\n          `Invalid technology tag: \"${tech}\". Valid tags: ${VALID_TECHNOLOGIES.join(\", \")}`\n        );\n      }\n    }\n  }\n\n  // Validate slug matches filename\n  if (data.slug) {\n    const expectedSlug = basename(filePath, \".md\");\n    if (data.slug !== expectedSlug) {\n      errors.push(\n        `Slug \"${data.slug}\" does not match filename \"${basename(filePath)}\". The slug must be \"${expectedSlug}\".`\n      );\n    }\n  }\n\n  // Validate URL format\n  if (data.website && !isValidUrl(data.website)) {\n    errors.push(","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/remoteintech/remote-jobs/blob/b1dd8deb1945e5ff58f9e9c35e318f53c8871930/.github/scripts/validate-companies.js#L120-L156","documentation":"Loop at lines 134-142 over data.technologies (only when it parsed as an Array). Each entry must appear in VALID_TECHNOLOGIES (keys of labels().tech from src/_data/labels.js). One error is pushed per invalid tag, so a profile with several bad tags reports each by name.","triggerScenarios":"A tag is misspelled ('javscript'); non-canonical casing ('JavaScript'); the array was entered as a comma-separated string rather than a YAML list (then data.technologies is a String, not an Array, so the check is silently skipped — see commonSituations); a tag was removed from labels.js but profiles still reference it.","commonSituations":"Contributor free-hands tags instead of copying from the allowed list; YAML indentation broken so technologies parsed as a scalar; tech taxonomy refactored in labels.js.","solutions":["Replace each invalid tag with the exact key from VALID_TECHNOLOGIES shown in the message.","Confirm the frontmatter list is a real YAML array (indented `- item` entries), not a comma-separated string.","If a tag was removed from labels.js, decide whether to re-add it or migrate profiles off it."],"exampleFix":"// before\ntechnologies:\n  - javscript\n  - py\n// after\ntechnologies:\n  - javascript\n  - python","handlingStrategy":"validation","validationCode":"const VALID_TECHNOLOGIES = Object.keys(labels().tech);\nfunction invalidTechs(list) {\n  return (Array.isArray(list) ? list : []).filter(t => !VALID_TECHNOLOGIES.includes(t));\n}","typeGuard":"function isTechnologiesArray(value) {\n  return Array.isArray(value) && value.every(t => Object.keys(labels().tech).includes(t));\n}","tryCatchPattern":null,"preventionTips":["Always format technologies as a YAML array (indented `- item`), not a comma-separated string.","Copy tech keys from labels.js; never invent new tags in a profile.","When removing a tag from labels.js, grep profiles and migrate them in the same change."],"tags":["enum","technologies","frontmatter","labels"],"backgroundTag":null,"analyzedSha":"b1dd8deb1945e5ff58f9e9c35e318f53c8871930","analyzedAt":"2026-08-13T04:09:00.804Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}