# Fix Google for Jobs Schema Errors and Warnings > Every Search Console and Rich Results Test error for JobPosting markup, what each message actually means, and the fix. Plus the warnings you can safely ignore. [Articles](/articles) Aug 6, 2026 / SEO & Growth / 11 min read # Google for Jobs Schema Errors: What Each Message Means [ Simon Gingras](/author/simon-gingras) Simon Gingras Founder, Kardow Simon built Kardow after years in B2B SaaS. He has launched niche job boards, writes about job board strategy, SEO, and monetization, and ships product daily. [View profile →](/author/simon-gingras) [LinkedIn ↗](https://www.linkedin.com/in/simon-gingras/) This page is a lookup table. Find the exact message Search Console or the Rich Results Test gave you, read what it actually means, apply the fix. If your markup validates cleanly and jobs still are not appearing, that is a different problem with a different cause, and it is covered in [why valid JobPosting schema still does not show in Google for Jobs](/articles/job-posting-schema-google-for-jobs). ## Start by Telling Errors From Warnings Most time lost in the Job Postings report is spent fixing things that were never broken. The report mixes two categories that look similar and mean completely different things. Google requires exactly five properties on a JobPosting: **title**, **description**, **datePosted**, **hiringOrganization**, and **jobLocation**. A missing one of those is an **error**, and the listing will almost certainly not appear. Everything else Google publishes, including validThrough, baseSalary, employmentType, identifier, jobLocationType, and applicantLocationRequirements, is **recommended**. A missing one of those is a **warning**, and the job remains eligible. That means the fastest triage is to sort by severity and ignore the warnings entirely on the first pass. A page showing eleven warnings and zero errors does not have a schema problem. ### Reading the message format Google reports nested problems with the parent in parentheses, as in `Missing field 'name' (in 'hiringOrganization')`. The part in parentheses tells you which object to open. Without it you would be searching the whole block for a property called name, and there can be several. ## Error Messages and What They Mean These block eligibility. Work top to bottom and re-test after each one, because a single malformed object often produces several messages at once and fixing the parent clears the children. | Message you see | What it actually means | Fix | | --- | --- | --- | | Missing field 'title' | No title property, or it is present but empty. Often happens when a template outputs the page heading but never writes the property. | Output the plain role title only. Not the city, not the salary, not "Apply now" or the company name appended to it. | | Missing field 'description' | The description property is absent or empty. Very common when the job body is loaded by JavaScript after the markup is written. | Include the full job description as an HTML string in the property. It must be the complete description, not a truncated preview. | | Missing field 'datePosted' | No posting date, or a format Google cannot parse. | Use ISO 8601, for example 2026-08-06. Use the genuine original posting date, not the date of your last re-publish. | | Missing field 'hiringOrganization' | The employer object is absent entirely. | Add hiringOrganization as an Organization object. A bare string will not satisfy it. | | Missing field 'name' (in 'hiringOrganization') | The employer object exists but has no name. The parenthetical tells you which nested object is at fault. | Set hiringOrganization.name to the real employer. Not your board's name, and not "Confidential" unless the employer is genuinely undisclosed. | | Missing field 'jobLocation' | No location, and no remote alternative supplied either. This is the single most common blocking error on remote roles. | On-site and hybrid roles need jobLocation with a PostalAddress. Fully remote roles need jobLocationType TELECOMMUTE plus applicantLocationRequirements instead. | | Missing field 'addressCountry' (in 'jobLocation.address') | An address object exists but is missing the country. Frequently caused by importing feeds that only carry city and state. | Add the two-letter country code. Fill addressLocality and addressRegion at the same time, since those are flagged separately as warnings. | | Invalid value or format in a date field | A date exists but is not parseable, usually a locale format like 06/08/2026 that is ambiguous between day and month. | Convert to ISO 8601 at the template level so no locale formatting reaches the markup. | | Invalid enum value in employmentType | A free-text value such as "Permanent" or "Full Time" where Google expects a fixed token. | Map to the allowed values: FULL_TIME, PART_TIME, CONTRACTOR, TEMPORARY, INTERN, VOLUNTEER, PER_DIEM, OTHER. | A title error is the one worth reading past the message on, because a title that is present but full of marketing copy raises no error at all and still costs you matches. That case is covered in [job title schema markup](/articles/job-title-schema-markup). One pattern accounts for a large share of these on job boards specifically: the markup is generated from one data source and the visible page from another. When a field is empty in the record the template reads, you get a missing-property error even though the information is sitting right there on the screen, pulled from somewhere else. If your errors cluster on a subset of jobs rather than all of them, that mismatch is the first thing to check. ## Warnings, and Which Ones to Ignore Warnings are suggestions. Some are worth acting on because they make listings more findable, and some genuinely do not matter. The distinction is whether you hold real data for the field. | Warning | Does it block your listing? | Worth fixing? | | --- | --- | --- | | Missing field 'validThrough' | No | Only if the job has a real expiry date. Inventing one is worse than omitting it, because a past validThrough removes the job from Google for Jobs. | | Missing field 'baseSalary' | No | Yes, when the employer publishes a salary and it is visible on the page. Salary is a filter candidates use heavily. Never estimate it to clear the warning. | | Missing field 'employmentType' | No | Yes. It is cheap to add, it is another filter candidates use, and you almost certainly already store it. | | Missing field 'identifier' | No | Worth adding if you have a stable internal job ID. It helps Google tell your listings apart when the same role is posted repeatedly. | | Missing field 'addressLocality' / 'addressRegion' / 'postalCode' / 'streetAddress' | No, as long as addressCountry is present | Add locality and region. Street address and postal code rarely matter for a job listing and can be left off. | | Missing field 'jobLocationType' or 'applicantLocationRequirements' | No for on-site roles. Effectively yes for remote ones. | For a fully remote role these two are what make it findable as remote. On an on-site role, ignore the warning. | The rule underneath all of these: never populate a field to silence a warning. A missing recommended property costs you a filter. An invented one is inaccurate markup, which is a policy matter. ## When the Markup and the Page Disagree This is the failure that produces no error message at all, which is what makes it dangerous. Google's documentation is explicit that all information in the markup must be visible on the job page. A validator only checks that your JSON parses and carries the right properties; it has no way to know whether the page backs up what the properties claim. | What the markup says | What the page shows | Why Google penalizes it | | --- | --- | --- | | A salary range | No salary anywhere on the page | Google requires that information in the markup be visible on the page. Invisible salary is a policy violation, not a formatting slip. | | A named employer | The board's own name, or "Confidential" | The listing gets attributed to the wrong organization, and repeat mismatches erode trust in every job on the domain. | | A specific city | A generic country page, or a filtered search result | The URL is not a single job detail page, so the location claim cannot be verified against it. | | A full description | A teaser with the rest behind a login or an expand button | Content gated behind interaction does not count as visible. | | datePosted from today | A job that has clearly been live for months | Refreshing the date to look current is exactly the pattern the expired-jobs policy is written to catch. | A quick way to catch these: open a job page, hide the markup, and try to fill in every property from what is visible on screen alone. Anything you cannot fill in is something Google cannot verify either. ## Expired Jobs Can Trigger a Manual Action Worth stating plainly because it is the most consequential item in this whole area and it is usually described as a best practice rather than what it is. Google's job posting documentation says that failure to take timely action on expired jobs may result in a **manual action**. That is a human reviewer penalizing the site, not an algorithmic ranking dip, and it can affect job listings across the entire domain rather than the stale pages alone. Google sanctions exactly three ways to retire a posting: 1. Set **validThrough** to a date in the past. 2. Return a **404** or **410** status code for the URL. 3. Remove the **JobPosting** markup from the page while leaving the page itself up. Any of the three is acceptable and they suit different situations. Use validThrough when you know the closing date in advance. Use 404 or 410 when the page has no reason to exist afterwards. Remove just the markup when you want to keep the URL alive for links or archives. What is not acceptable is the fourth option most boards default to by accident: leaving the closed job live with its markup intact because nothing in the system triggers a cleanup. ## Duplicate Job URLs The same job reachable at several URLs splits its signals and can make every copy ineligible. On job boards this rarely comes from deliberate duplication. It comes from filter and sort parameters producing new URLs, from the same feed being ingested through two sources, from tracking parameters on shared links, and from a job appearing under more than one category path. Google's instruction for this case is direct: use canonical URLs on each copy of the page, pointing at the one version you want indexed. The practical work is deciding which URL is canonical and making the rule automatic, because doing it by hand does not survive contact with a feed that adds a few hundred jobs a week. ## Rebuild the Markup Cleanly If the errors have accumulated to the point where patching individual properties is not obviously converging, it is often faster to generate a known-good block for one job, confirm it validates, then work backwards to make your template produce that shape. The generator below builds a valid JobPosting block with the required properties in place and the remote and on-site branches handled correctly. Free JobPosting schema generator Fill in the fields. Valid JSON-LD updates live. No sign-up, runs in your browser. Job title Job description Employer name Employer website Date posted Valid through (optional) Employment type Full time Part time Contractor Temporary Intern Volunteer Per diem Other Location type On-site Hybrid Fully remote City Region / state Postal code Country (e.g. US) Applicants may work from (country) Currency Salary min Salary max Per Hour Day Week Month Year Only add salary if it is real and visible on the job page. job-posting.jsonld Paste the copied `