9.0.0 (2026-08-25)¶
Summary¶
The main focus of the 9.0.0 release is project rules - rules that read the whole project context instead of a
single file. We added 12 project rules (argument, import, keyword and variable checks across files) and merged
the separate robocop check-project command into the regular robocop check.
Beyond project rules, this is a large release with several other big changes:
- 13 new non-project rules, including a dedicated
GROUPsyntax category, continue-on-failure tag rules and new spacing/documentation/variable checks. - Fixes for more than 35 rules, letting Robocop auto-correct many issues and replacing several redundant formatters (leaner formatters focused on alignment and whitespace).
- Plugins - custom rules, formatters, reports and configuration can now be packaged and distributed as plugins.
- Built-in rulesets - reference curated rule sets with
extends = ["robocop:minimal"]. - Custom reports - load and enable your own reports just like custom rules and formatters.
robocop config init- generate a fully documented configuration file.- Test case
[Metadata]support (Robot Framework 7.5) across the linter and the formatter. - New
AlignBDDStatementsformatter - leaner, fixed-width whitespace alignment.
Breaking changes¶
Deprecated formatters¶
Removed formatters:
- ReplaceEmptyValues (replaced by the fix for the
empty-variablerule) - RemoveEmptySettings (replaced by the fix for the
empty-*rules - LEN11-LEN26, LEN29-LEN31, TAG08, MISC02) - NormalizeComments (replaced by the fix for the
missing-space-after-commentrule) - ReplaceRunKeywordIf (replaced by the fix for the
deprecated-run-keyword-if(DEPR08) rule) - NormalizeAssignments (replaced by the fixes for the
inconsistent-assignment(MISC04) andinconsistent-assignment-in-variables(MISC05) rules.) - DiscardEmptySections (replaced by the fix for the
empty-section(LEN09) rule. Note that, unlike the formatter'sallow_only_comments=Falseoption, the rule fix never removes sections that contain comments.) - ReplaceBreakContinue (replaced by the fix for the
deprecated-loop-keyword(DEPR09) rule)
The functionality of the above formatters is now fully replaced by the corresponding rule fixes, and those formatters became redundant. It's part of an ongoing process to deliver more rule fixes while keeping formatters leaner. Ideally, a formatter should focus on alignment or whitespace, not on replacing/rewriting the code.
Deprecated if-can-be-used rule¶
It only worked for Robot Framework versions we don't support anymore.
Its functionality is replaced by the deprecated-run-keyword-if rule.
Deprecated robocop check-project command¶
This release focuses on implementing project rules. It became clear that keeping project rules in a separate command
does not make sense. It requires the user to run robocop twice, merge reports, etc. Now you can run project rules
by simply selecting them by name/id or using the 'PROJECT' keyword (robocop check --select PROJECT).
Project checkers have a new signature¶
Refactored how a project checker works, which may affect custom rules. Now the scan_project method accepts a
context argument which contains the accumulated project context (it's now done automatically by robocop if a
project rule is enabled).
Leaner whitespace alignment – fixed width¶
Robocop used a special algorithm when calculating whitespace alignment in various formatters. The idea was to keep the whole width of a 'column' (setting/name + whitespace) as a multiple of 4. It made writing the code slightly easier (so you could more easily TAB to the next column) but was confusing to users and also produced wider lines than necessary.
Now the separator uses a fixed minimum of 4 spaces (the default min_separator). For example, if you had a
6-character-long name:
Previously, the column was rounded up to the next multiple of 4, so it was aligned to at least 12 characters (6 + 4 = 10, rounded up to 12):
And now it is simply 10 characters (6 + 4) at minimum (the line will still be aligned to the other lines as well):
While it is not a breaking change itself, it may result in multiple file changes after the Robocop update.
Features¶
New project rules¶
The main focus in 9.0.0 is project rules. Robocop is now capable of reading project context and uses it for a set of new rules.
To support it, we now have several new commands and options:
robocop list rules --filter PROJECTlists all project rules--project/--no-projectto enable/disable running project rules. By default, robocop runs project rules if they are selected, but it may be disabled with--no-project--analyze-libraries/--no-analyze-libraries- robocop imports libraries to check the keywords they provide. Use this option to disable it if you're using project rules but do not want to import libraries (in exchange, robocop will not find related issues)--load-library-timeout <SECONDS>- maximum time for importing a single library (default 10). Only used together with--library-workers--library-workers/--no-library-workers- use it to import libraries in parallel, in a separate process with a timeout. It is useful when you have multiple libraries that take a long time to import--ignored-library <NAME>- library that should not be imported. Supports glob patterns--pythonpath/-P <PATH>- additional locations to search for resources, variable files and libraries. Equivalent of the Robot Framework option.--variable/-v <NAME:VALUE>- set a variable used to resolve dynamic import paths. Equivalent of the Robot Framework option.--variablefile/-V <NAME:VALUE>- Python or YAML file with variables used to resolve dynamic import paths. Equivalent of the Robot Framework option.
All project rules are optional – not everything may fit the code guidelines in your project.
The following rules were added:
- ARG08
invalid-argument-count: Keyword is called with a wrong number of arguments
Example of rule violation:
*** Test Cases ***
Scenario 1
Keyword Call 1
*** Keywords ***
Keyword Call
[Arguments] ${arg1} ${arg2}
- ARG09
missing-argument-name: Keyword is called with a positional argument instead of a named one
Example of rule violation:
*** Test Cases ***
Scenario 1
Keyword Call arg1=value value2
*** Keywords ***
Keyword Call
[Arguments] ${arg1} ${arg2}
- DUP11
duplicated-variable-in-project: Variable with the same name defined in multiple files visible together
Robot Framework does not report an error when the same variable is defined in a suite and in a resource file imported by it, or in two resource files imported by the same suite. The value used at runtime depends on the import order, which makes such duplications a common source of hard to debug problems.
Example of rule violation:
*** Settings ***
Resource variables.resource
*** Variables ***
${BROWSER} firefox # variables.resource also defines ${BROWSER}
- IMP05
unused-resource-import: Imported resource file is not used.
Reports resource imports whose keywords and variables are never used in the importing file.
Example of rule violation:
*** Settings ***
Resource unused.resource # nothing from this file is used
*** Test Cases ***
Test
Keyword From Other Resource
- IMP06
unused-library-import: Imported library is not used
Reports library imports whose keywords are never used in the importing file.
Example of rule violation:
*** Settings ***
Library Collections # no keyword from this library is used
*** Test Cases ***
Test
Log message
- IMP07
unresolved-resource-import: Imported resource file does not exist
Reports resource imports that point to a file that cannot be found in the project. Such import makes the whole suite fail during the execution.
Example of rule violation:
- IMP08
circular-import: Resource file is a part of a circular import
Reports resource imports that import, directly or indirectly, the file they are used in.
Example of rule violation:
# keywords.resource
*** Settings ***
Resource helpers.resource
# helpers.resource
*** Settings ***
Resource keywords.resource # keywords.resource imports this file already
- IMP09
unresolved-library-import: Imported library could not be imported
Reports library imports that Robot Framework would not be able to import during the execution.
Example of rule violation:
*** Settings ***
Library libs/does_not_exist.py # file is not found next to the importing file
Library NotInstalledLibrary # module is not installed and is not found in the search paths
- KW04
unused-keyword: Keyword is not used
Reports keywords that are defined in the project but never called.
Example:
*** Test Cases ***
Test that only non used keywords are reported
Used Keyword
*** Keywords ***
Used Keyword
Log used
Not Used Keyword # this keyword will be reported as not used
[Arguments] ${arg}
Should Be True ${arg}>50
- KW05
keyword-not-found: Keyword is not defined anywhere
Reports keyword calls that do not match any keyword defined in the file, in the imported resource files or in
the imported libraries. Robot Framework fails such call with the No keyword with name 'X' found error.
Example of rule violation:
*** Settings ***
Resource login.resource # defines Login
*** Test Cases ***
Test
Login user password
Logout # Logout is not defined anywhere
- KW06
ambiguous-keyword-name: Keyword name matches more than one keyword
Reports keyword calls that match keywords defined in more than one place. Robot Framework fails such call
with the Multiple keywords with name 'X' found error, unless the call uses the full name of the keyword.
Example of rule violation:
*** Settings ***
Resource login.resource # defines Login
Resource admin.resource # defines Login as well
*** Test Cases ***
Test
Login user password # it is not known which keyword should be used
- KW07
missing-keyword-prefix: Keyword is called without the name of the resource file or library it comes from
Optional rule for projects that require every keyword call to be prefixed with the source of the keyword. Such calls are unambiguous and it is immediately clear where the keyword comes from:
*** Settings ***
Resource login.resource
Library SeleniumLibrary
*** Test Cases ***
Test
Login user password # will be reported
Click Element id:submit # will be reported
login.Login user password # explicit, not reported
SeleniumLibrary.Click Element id:submit
New AlignBDDStatements formatter (#1451)¶
New, non-default formatter that aligns BDD statements in the test case body. Keyword calls prefixed with the BDD
reserved keywords (Given, When, And, But and Then) are indented so the keyword names following
the prefixes are aligned in a single column:
*** Test Cases ***
There can be only one
Given there are 3 ninjas
And there are more than one ninja alive
When 2 ninjas meet, they will fight
Then one ninja dies (but not me)
And there is one ninja less alive
Enable it with robocop format --select AlignBDDStatements. See
AlignBDDStatements documentation for more details.
AlignTemplatedTestCases arguments placement (args_with_test)¶
AlignTemplatedTestCases now exposes an args_with_test parameter that controls whether template arguments and
settings stay in the same line as the test case name. Possible values are split (new default),
split_on_settings and keep:
splitalways moves template arguments and settings to their own line, keeping only the test case name in the first line. Test case names are ignored when calculating the column widths (header names are still respected) and settings are no longer counted towards the column widths.split_on_settingsmoves template arguments and settings to their own line only if the test case contains any setting (such as[Tags]or[Documentation]).keepkeeps template arguments and settings in the same line as the test case name (the previous behaviour). When header names are present, the first body row is pulled up to the test case name line.
Test cases that contain block structures (FOR, IF, TRY, WHILE) are always split, regardless of the
selected mode. Additionally, [Documentation] no longer affects the calculated column widths.
Since the default changed to split, updating Robocop may reformat existing templated test cases. Configure
AlignTemplatedTestCases.args_with_test=keep to preserve the previous layout. See
AlignTemplatedTestCases documentation for more details.
Support for test case metadata (Robot Framework 7.5)¶
Upcoming Robot Framework 7.5 allows using the [Metadata] setting inside test cases:
*** Test Cases ***
Test
[Documentation] Doc.
[Metadata] Requirement REQ-42
[Metadata] Component Login
Keyword
Robocop now recognizes it in both the linter and the formatter:
[Metadata]is accepted byERR09 setting-not-supportedwhen running with Robot Framework 7.5 or newerDUP06 duplicated-metadatanow reports duplicated metadata per test case, instead of mixing test case metadata with the suite metadata. Previously, the same metadata name used in two different test cases was incorrectly reported as a duplicateLEN11 empty-metadataand the newLEN33 metadata-without-valuerule work with test case metadataNAME05 setting-name-not-in-title-casenow also validates theMetadata/[Metadata]setting nameSPC19 not-enough-whitespace-after-settingnow also reports the[Metadata]settingORD01 test-case-section-out-of-ordersupports the newmetadatavalue. The default order is nowdocumentation,metadata,tags,timeout,setup,template,keyword,teardownOrderSettingsformatter orders[Metadata]right after[Documentation]. Itstest_beforedefault is nowdocumentation,metadata,tags,timeout,setup,template. The formatter also no longer removes repeated settings, which previously would have dropped all but the last[Metadata]AlignTestCasesSectionformatter aligns[Metadata]together with the other test case settings. It can be disabled with--skip metadataorAlignTestCasesSection.skip_metadata=True
New rules¶
GROUP syntax rules (#1159)¶
Robot Framework 7.2 added the GROUP syntax. Robocop now ships a dedicated GRP rule category for it:
- GRP01
too-few-calls-in-group:GROUPwith too few keyword calls inside (configurable withmin_calls, defaults to2so groups wrapping a single keyword are reported) - GRP02
too-many-calls-in-group:GROUPwith too many keyword calls inside (configurable withmax_calls, defaults to10) - GRP03
group-without-name:GROUPused without a name - GRP04
nested-group:GROUPnested inside anotherGROUP(disabled by default)
Empty and unterminated GROUP blocks are now reported by the parsing-error rule.
Disallow the GROUP syntax (#1158)¶
- GRP05
group-not-allowed: reports every use of theGROUPsyntax (disabled by default). Enable it to keep your project compatible with Robot Framework versions older than 7.2 or when your team decided not to use groups.
continue-on-failure tag rules (#1882)¶
Rules related to robot:continue-on-failure tag:
- TAG12
unnecessary-continue-on-failurereportsRun Keyword And Continue On Failurecalls in tests and keywords that already enable the continue on failure mode with a tag. - TAG13
could-be-continue-on-failure-tagreports tests and keywords where every keyword call is wrapped inRun Keyword And Continue On Failureand therobot:continue-on-failuretag could be used instead.
empty template data line rule (#999)¶
New SPC23 empty-line-in-test-template rule (with a fix) that reports on:
Metadata without value rule¶
New LEN33 metadata-without-value reports metadata with a name but without a value.
Example of rule violation:
Such metadata is resolved to an empty value, which is almost always a mistake. Use LEN11 empty-metadata
to detect metadata without a name.
Empty lines inside block rule (#1891)¶
New SPC24 empty-lines-inside-block that reports on:
Automatic variable availability rule (#1867)¶
New VAR13 automatic-variable-not-available rule that reports automatic variables used in a context where they are
not available (for example, using ${TEST_NAME} outside of a test case).
Variable in documentation rule (#1866)¶
New DOC05 variable-in-documentation rule (disabled by default) that detects unescaped variables used in
documentation.
Whitespace around comparison operator rule (#1762)¶
New MISC16 not-enough-whitespace-around-operator rule that reports comparison operators (==, !=, >,
<, >=, <=) used in conditions without surrounding whitespace. It inspects the conditions of IF and
WHILE blocks as well as the conditions passed to BuiltIn keywords such as Should Be True or Skip If. The
missing whitespace can be added automatically with the --fix option:
*** Test Cases ***
Test
IF ${variable}==5 # reported: should be '${variable} == 5'
Log Robocop
END
New fixes for rules¶
Several rules now have fixes:
deprecated-run-keyword-if(#1898)inconsistent-assignmentinline-if-can-be-usedduplicated-variable(#1857)else-not-upper-case(#1854)empty-return(#1846)empty-section(#1841)empty-tags(#1842)unnecessary-default-tags(#1850)unused-disabler(#1855)missing-space-after-comment(#1844)ignored-data(#1844)inconsistent-assignment-in-variables(#1859)misplaced-negative-condition(#1859)deprecated-with-name(#1843)deprecated-singular-header(#1843)duplicated-resource(#1848)duplicated-library(#1848)duplicated-variables-import(#1848)empty-*18 rules (#1840)empty-library-alias(#1847)duplicated-library-alias(#1847)empty-variable(#1852)undefined-argument-default(#1852)wrong-import-order(#1856)builtin-imports-not-sorted(#1856)tag-already-set-in-test-tags(#1851)duplicated-tags(#1851)tag-already-set-in-keyword-tags(#1851)setting-name-not-in-title-case(#1858)section-name-invalid(#1858)wrong-case-in-keyword-name(#1860)wrong-case-in-keyword-call(#1860)not-enough-whitespace-after-setting(#1862)not-enough-whitespace-after-newline-marker(#1862)not-enough-whitespace-after-variable(#1862)
Plugins (#1538)¶
Custom rules, formatters and configuration files can now be packaged and distributed as a Robocop plugin.
A plugin is a regular Python package that registers itself using the robocop.plugins entry point group:
[project]
name = "example-plugin"
[project.entry-points."robocop.plugins"]
example = "example_plugin.path.to.dir"
Robocop discovers installed plugins automatically. Use robocop list plugins to see them.
The entry point name becomes the plugin namespace, and its resources are referenced with the
<plugin_name>.<path.inside.the.plugin> syntax:
[tool.robocop]
extends = ["example.config.strict"]
[tool.robocop.lint]
custom_rules = ["example.rules"]
reports = ["example.reports"]
[tool.robocop.format]
select = ["example.formatters.FormatterA"]
Installing a plugin does not enable anything on its own - it only registers the namespace, so plugin resources can be referenced in the configuration.
Note that extends values that do not end with .toml were previously silently ignored. They are now
resolved as plugin references, and Robocop reports an error if the plugin or its configuration file is missing.
See the plugins documentation for more details.
Built-in rulesets (#1523)¶
Robocop ships with built-in rulesets that can be referenced using the robocop:<name> syntax in extends:
Currently, there is only one built-in ruleset available - robocop:minimal, a curated, minimal set of rules focused
on correctness and runtime issues. It selects only the rules from this set and overrides their default severity with
the one defined by the ruleset.
Just like any other configuration, a built-in ruleset can be extended and overridden. For example, to use the
minimal ruleset but add an extra rule:
As part of this change, several rules have updated severity values (in default configuration). We will monitor and analyze the best mappings and add next rulesets in upcoming releases.
Custom reports (#1115)¶
Reports can now be defined outside Robocop, in the same way as the custom rules and formatters. Custom reports are
enabled with the existing --reports option by pointing it to the source of the reports: a path to the Python
file or a directory, an importable module or a plugin reference:
All reports found in the source are loaded and enabled. Custom report is a class that inherits from the
robocop.linter.reports.Report class and defines the name and the description attributes. Such report
can be configured (--configure custom_report.param=value), listed (robocop list reports) and documented
(robocop docs custom_report) exactly like the built-in reports.
See the reports documentation for more details.
Generate a configuration file (#897)¶
New robocop config init command generates a documented configuration file with all the available options.
The generated robocop.toml lists every global option, linter rule and formatter together with their default
values and a short description. All options are written as comments, so the generated file reproduces Robocop's
default behaviour until you uncomment and edit the options you want to change:
robocop config init # write robocop.toml in the current directory
robocop config init --force # overwrite an existing file
robocop config init --output config.toml # write to a custom location
robocop config init --output - # print to the standard output
See the configuration documentation for more details.
Fixes¶
- Run Keywords variants are now properly resolved when used with a BDD prefix (#1877)
- empty and unterminated GROUP parse errors are now reported (#1895)
- replaced the deprecated GitWildMatchPattern with GitIgnoreSpec (#1887)
not-allowed-char-in-filename(file-wide rule) prints source code on report (#1871)- check the
VARassignment sign in theinconsistent-assignmentrule (#1902) - strip whitespace in comma-separated formatter parameters so values like
imports_order=library, resource, variablesare accepted (#1922)
Other¶
- allow to skip report file generation on empty results (#1835)
inconsistent-assignment(MISC04) rule now also checks the assignment sign in theVARsyntax- add
ignored_docsparameter toline-too-long(#1892) - align only first column of documentation in
AlignSettingsSection(#1890) - keep comments together with the closest keyword/argument in
IndentNestedKeywords(#1919)
Refactors¶
Combined several checkers (for better control and performance), split rules from checkers with dedicated responsibility (visitors separately from rule checks) in the following PRs:
- merge control flow checkers into single ControlFlowChecker (#1818)
- merge deprecated statement checker into settings checker (#1820)
- merge keyword and variable naming checkers (#1819)
- merge keyword argument checkers into a single checker (#1808)
- merge keyword body checkers into a single checker (#1812)
- merge keyword call checkers into a single checker (#1807)
- merge raw file checkers into a single checker (#1806)
- merge section-level checkers into single SectionsChecker (#1813)
- merge settings checkers into single SettingsChecker (#1817)
- merge tag checkers into single TagsChecker (#1815)
- merge test case and keyword checkers into TestCaseKeywordChecker (#1814)
- merge variable statement checkers into single VariablesChecker (#1816)
- move linter checkers to a dedicated package (#1821)