Rules / Report Design

Hardcoded year in a filter

info HARDCODED_YEAR_IN_FILTER · built in · report layer · scope: Visual, Page, Report

What it checks

Filters in the Filters pane, on a visual, a page, or all pages, that hold a year column to fixed years: years picked in Basic filtering, a year set with Advanced filtering's is, years kept up to one with is less than or is less than or equal to, and a range between two years.

A year column is a column, or a level of a hierarchy, whose name says it holds a year, in several languages: Year, Fiscal Year, Año, Ano, Jahr, Année, and more, the same words HARDCODED_PERIOD_IN_DAX reads in DAX. A year is a whole number or text of four digits, from 1950 to 2049.

Each finding names what the filter is on: a visual as "Sales LY" on "Overview", or as card (3d9c80) on "Overview" when it has no title; a page's filter as Page filter on "Overview"; and a filter on all pages as Report filter. Its detail says what the filter keeps, and on which column, as fixed year 2025 on 'Date'[Year], fixed years 2024 and 2025 on 'Date'[Year], years up to 2025 on 'Date'[Year], or years 2018 to 2025 on 'Date'[Year]. The finding sits on the line of report.json, the page.json, or the visual.json where the year is written: the first year kept, or the upper bound.

Example

Fires the rule in page.json
{
  "$schema": "https://developer.microsoft.com/json-schemas/fabric/item/report/definition/page/2.1.0/schema.json",
  "name": "3cea48e58036b1654474",
  "displayName": "Overview",
  "displayOption": "FitToPage",
  "height": 720,
  "width": 1280,
  "filterConfig": {
    "filters": [
      {
        "name": "21d1dc168996da6409ea",
        "field": { "Column": { "Expression": { "SourceRef": { "Entity": "Date" } }, "Property": "Year" } },
        "type": "Categorical",
        "filter": {
          "Version": 2,
          "From": [{ "Name": "d", "Entity": "Date", "Type": 0 }],
          "Where": [
            {
              "Condition": {
                "In": {
                  "Expressions": [
                    { "Column": { "Expression": { "SourceRef": { "Source": "d" } }, "Property": "Year" } }
                  ],
                  "Values": [[{ "Literal": { "Value": "2025L" } }]]
                }
              }
            }
          ]
        },
        "howCreated": "User"
      }
    ]
  }
}
After the fix in page.json
{
  "$schema": "https://developer.microsoft.com/json-schemas/fabric/item/report/definition/page/2.1.0/schema.json",
  "name": "3cea48e58036b1654474",
  "displayName": "Overview",
  "displayOption": "FitToPage",
  "height": 720,
  "width": 1280,
  "filterConfig": {
    "filters": [
      {
        "name": "f7a189206cee6051586c",
        "field": { "Column": { "Expression": { "SourceRef": { "Entity": "Date" } }, "Property": "Date" } },
        "type": "RelativeDate",
        "filter": {
          "Version": 2,
          "From": [{ "Name": "d", "Entity": "Date", "Type": 0 }],
          "Where": [
            {
              "Condition": {
                "Comparison": {
                  "ComparisonKind": 0,
                  "Left": { "Column": { "Expression": { "SourceRef": { "Source": "d" } }, "Property": "Date" } },
                  "Right": { "DateSpan": { "Expression": { "Now": {} }, "TimeUnit": 3 } }
                }
              }
            }
          ]
        },
        "howCreated": "User"
      }
    ]
  }
}

The Overview page was saved with 2025 picked for 'Date'[Year] under Filters on this page, so the finding reads Page filter on "Overview" with fixed year 2025 on 'Date'[Year]. The fix filters 'Date'[Date] instead, with a relative date filter that keeps the dates in this year. Nothing in it names a year, so on January 1 the page moves to the new one by itself.

Why it matters

A filter set in the Filters pane is saved with the report, and Microsoft says such filters "become the default filter state for all your report readers" (Reset to default values). A year picked there is right for the year it was saved in and quietly wrong after it. A page filtered to 2026 still shows 2026 all through 2027, under the same titles, and nothing on it says the year has passed.

A filter that keeps years up to one, or years picked one by one, goes wrong more quietly still. When a new year's data arrives the filter leaves it out, and the visuals look complete without it. A hidden filter is the hardest to catch: in Microsoft's words, "If you hide the filter, they can't even see it" (Lock or hide filters).

How to fix it

Filter the date, not the year, with a filter that moves with the calendar. In Power BI Desktop:

  1. Drag the date column, such as 'Date'[Date], from the Data pane into the section of the Filters pane that holds the year filter: Filters on this visual, Filters on this page, or Filters on all pages (Add a filter to a visual).
  2. On the date column's filter card, select Relative date from the Filter type drop-down (Create the relative date range filter).
  3. Under Show items when the value, choose is in this, then year.
  4. Remove the year filter. A filter you added can be deleted from the pane; a year that is one of the visual's own fields cannot be deleted, since the visual refers to it, so clear it instead (Types of filters).

A relative date filter needs a column whose data type is a date, and it cannot use the auto date/time hierarchy, so for a filter on a date column's Year level, filter that date column itself (Considerations and limitations).

When the filter keeps every year up to the latest one, as a range, an upper bound, or years picked one by one, it usually means every year from the first on. On its card, choose Advanced filtering, set the first condition to is greater than or equal to the first year, leave the second empty, and select Apply filter (Add a filter to a visual), so each new year is kept as it arrives.

When the page should follow the latest year in the data rather than the calendar, as when data for a year lands weeks after it starts, or when the model has no date column, mark the year in the model instead. Right-click the date table in the Data pane, select New column, and enter the column's DAX in the formula bar (Using calculated columns):

Is Latest Year = 'Date'[Year] = YEAR ( MAX ( Sales[Order Date] ) )

Then drag Is Latest Year into the Filters pane in place of the year filter and keep True. For the calendar's current year, write YEAR ( TODAY () ) in place of the MAX. Either way the flag moves at the first refresh of the new year, since, as Microsoft puts it for calculated columns, "Column values are recalculated as necessary, like when the underlying data is refreshed and values have changed" (Using calculated columns).

In the report's files, the filter is an entry in filterConfig in report.json for all pages, the page.json for a page, or the visual.json for a visual: replace the year's entry with one on the date column, as the example does.

When to ignore it

A fixed year is sometimes the point: a page or a visual about one year, such as a review of 2024; a baseline year others are compared with; a cohort; a series that has ended, such as figures that stopped being published; or sample data that never changes.

Often the better move is a name that says so. A page whose name, or a visual whose title, carries one of the years its filter keeps, such as Sales 2024 or Review FY24, reads as deliberate to every reader, and the rule leaves that filter alone.

To ignore this rule on one page or visual, add { "name": "pbiplint.ignore", "value": "HARDCODED_YEAR_IN_FILTER" } to the annotations array of its page.json or visual.json. Power BI Desktop keeps the annotation. To turn the rule off for a whole project, set "HARDCODED_YEAR_IN_FILTER": "off" under rules in pbiplint.config.json.

Quirks

Check a report for this Improve this page