Analyzing Code
robotcode analyze code performs static analysis on a Robot Framework project: it parses the .robot and .resource files, resolves their imports, libraries, and variables, and reports diagnostics for problems such as unknown keywords, unresolved variables, wrong argument counts, duplicate or failing imports, and deprecated syntax. No tests are executed.
The analysis is performed by the same code that powers the RobotCode language server, so the diagnostics are identical to the ones shown in the editor (the VS Code extension, the IntelliJ plugin, or any other LSP client); analyze code applies that analysis to the whole project from the command line. Configuration and profile resolution work the same as for robotcode robot, so imports and variables resolve as they would at run time. The result is printed as a human-readable list or, for CI use, as a structured report (JSON, SARIF, GitHub annotations, or GitLab Code Quality).
Which diagnostics are reported, and at what severity, can be configured per project or inline in the source; this is shared with the language server and documented separately in Controlling Diagnostics with Modifiers.
Who this is for:
- Developers who want a fast "is my project sound?" check before committing or running anything.
- CI/CD pipelines that want to fail a build on broken keyword references or upload findings to a code-scanning dashboard.
- Code review / security tooling — the SARIF output plugs straight into GitHub code scanning; the GitLab format into Merge Request Code Quality widgets.
- AI-driven workflows — a coding agent gets a precise, machine-readable list of what's wrong instead of having to run the suite and parse a traceback.
This guide covers analyze code. The analyze group has one other subcommand, cache, for inspecting and clearing the on-disk analysis cache — covered briefly at the end.
For the exhaustive, auto-generated option list see the CLI reference.
Quick start
Section titled “Quick start”# Analyze the whole projectrobotcode analyze code
# Analyze a specific folder or filerobotcode analyze code tests/acceptancerobotcode analyze code tests/acceptance/login.robot
# Only look at certain filesrobotcode analyze code --filter "**/*.resource"
# Also report unused keywords and variablesrobotcode analyze code --collect-unused
# Treat a specific diagnostic as ignored / as an errorrobotcode analyze code -mi MultipleKeywordsrobotcode analyze code -me VariableNotFound
# Machine-readable outputrobotcode analyze code --output-format jsonrobotcode analyze code --output-format sarif --output-file robotcode.sarifIf you don't pass any paths, analyze code analyzes the whole project — every .robot / .resource file under the project root, minus the configured exclude patterns, the paths excluded by .robotignore or .gitignore, and hidden files and folders. (This is unlike robotcode robot, which would run only the default paths/suites from your profile.)
How analyze code finds your project
Section titled “How analyze code finds your project”analyze code reuses the full RobotCode configuration pipeline:
- It locates the project root and the
robot.toml/pyproject.tomlfiles the same way every otherrobotcodecommand does. - It applies the active profile(s) (
--profile) and the[tool.robotcode-analyze]settings. - It honours
--variable,--variablefileand--pythonpath(mirroring the correspondingrobotoptions) so that imports and variable resolution behave exactly as they would at run time.
This matters: a keyword that only resolves because of a --pythonpath entry or a variable file resolves during analysis too, instead of being wrongly reported as missing.
Imports and libraries are resolved only for the files selected by paths / --filter, and the per-file diagnostics are computed only for those files, so a narrower selection makes a run faster.
What it checks
Section titled “What it checks”The diagnostics are exactly those the language server produces. Among the most common:
KeywordNotFound— a keyword call that resolves to nothing.MultipleKeywords— an ambiguous keyword name matching several definitions.VariableNotFound/VariableNotReplaced— references to variables that don't exist or can't be resolved statically.- import diagnostics —
LibraryAlreadyImported,ResourceAlreadyImported,ImportContainsErrors, circular imports,LibraryLoadedWithoutArguments(information: the library could not be initialized with the import's arguments, so its keywords come from loading it without arguments),LibraryImportIgnored(warning, Robot Framework 7.4+: Robot Framework ignores the library import, because an earlier import already uses its name for another library or with other arguments), … - deprecation warnings —
DeprecatedReturnSetting,DeprecatedHeader,DeprecatedHyphenTag,TagsWithoutEmptyRow(aTags:section in a keyword's documentation without an empty row before it, Robot Framework 7.5+), … - model errors — empty tests/keywords, invalid headers, and other structural problems.
This is static analysis, so it isn't the last word: actually running the suite — or even discovering it with robotcode discover — can surface errors that analyze code doesn't. Building the real test suite runs additional, suite-wide checks (for example duplicate test case names), and a PreRunModifier may have changed the suite before it's executed — neither of which the per-file static analysis sees. A clean analyze code result is a strong signal, not a guarantee that a run will start without errors.
Unused keywords and variables
Section titled “Unused keywords and variables”By default analyze code does not flag unused definitions. Unlike the per-file diagnostics, deciding whether a keyword or variable is unused needs the reference data of the whole project: with paths / --filter, only references inside the selected files count, and anything used only outside them is reported as unused, so run it on the whole project. It also adds an extra pass that is noticeably slower on projects with many keywords and variables. Enable it explicitly:
robotcode analyze code --collect-unusedThis adds two diagnostics:
KeywordNotUsed— a keyword defined in the project that nothing references.VariableNotUsed— a variable/argument that's never read. Names that are intentionally unused (${_},${_ignored}) are skipped.
They behave like any other diagnostic — you can remap or ignore them with the modifiers (e.g. -mh KeywordNotUsed) or # robotcode: comments.
You can also turn this on permanently in robot.toml:
[tool.robotcode-analyze.code]collect-unused = trueSeverities and diagnostic modifiers
Section titled “Severities and diagnostic modifiers”Every diagnostic has one of four severities — Error, Warning, Information, Hint — and you can remap any diagnostic code to a different severity (or silence it entirely). On the command line:
| Flag | Effect |
|---|---|
-mi, --modifiers-ignore CODE |
Ignore this diagnostic code entirely |
-me, --modifiers-error CODE |
Treat as Error |
-mw, --modifiers-warning CODE |
Treat as Warning |
-mI, --modifiers-information CODE |
Treat as Information |
-mh, --modifiers-hint CODE |
Treat as Hint |
Each flag can be given multiple times. The same mapping is available — and usually better kept — in robot.toml:
[tool.robotcode-analyze.modifiers]ignore = ["VariableNotFound"]error = ["MultipleKeywords"]hint = ["KeywordNotUsed"]* is a wildcard that matches every code, so -mi "*" silences all diagnostics. Re-introducing specific codes at a chosen severity then gives you an allow-list:
# show only KeywordNotFound — reported as a warningrobotcode analyze code -mi "*" -mw KeywordNotFoundThis is a remap (the kept codes take the severity you assign). If you instead want to keep a code at its original severity, use the --code filter.
Because the severity is configurable, the text and SARIF/GitHub/GitLab output always carries the effective severity, not a hard-coded one. For the full modifier system — including inline # robotcode: comments — see Controlling Diagnostics with Modifiers.
Reporting only some diagnostics
Section titled “Reporting only some diagnostics”Two flags narrow the result to a subset. Unlike the modifiers above (which remap a code's severity), these filter: whatever you don't list is dropped from the output, the summary and the exit code alike — the severity of what remains is unchanged.
--severity— keep only the given severities. Values:error,warn/warning,info/information,hint.--code— keep only the given diagnostic codes (e.g.KeywordNotFound); matching is case-insensitive.
Both are repeatable and comma-separated. When both are given they combine with AND — a diagnostic must match both.
robotcode analyze code --severity warning,hint # only warnings and hintsrobotcode analyze code --code KeywordNotFound # only KeywordNotFound, with its real severityrobotcode analyze code --code KeywordNotUsed --severity hint # only KeywordNotUsed that are hintsWhen neither is given, everything is reported.
Exit codes
Section titled “Exit codes”analyze code exits with a bitwise combination of these values, so a single status tells you which severities were present:
| Value | Name | Meaning |
|---|---|---|
0 |
SUCCESS |
nothing reported |
1 |
ERRORS |
at least one error |
2 |
WARNINGS |
at least one warning |
4 |
INFOS |
at least one information |
8 |
HINTS |
at least one hint |
For example, errors and warnings give 1 | 2 = 3.
To stop certain severities from affecting the exit code — e.g. so warnings don't fail the build — use an exit-code mask:
# Warnings/infos/hints no longer change the exit code; only errors dorobotcode analyze code --exit-code-mask warn,info,hint
# Same, but additive to the mask configured in robot.tomlrobotcode analyze code --extend-exit-code-mask hintValid mask values: error, warn (alias warning), info (alias information), hint, all. In robot.toml:
[tool.robotcode-analyze.code]exit-code-mask = ["warn", "info", "hint"] # CI fails only on errorsA non-zero exit means that something was reported, which is what makes a CI step fail by default, or that the command failed: a usage error, such as an invalid option value or a missing --output-file directory, exits with 2, and other failures, such as an invalid robot.toml, exit with 1. To branch on a specific severity, make sure a report was written, then test the corresponding bit — in bash:
robotcode analyze code | tee analyze.txtcode=${PIPESTATUS[0]}[ -s analyze.txt ] || exit "$code" # nothing written: the command itself failed(( code & 1 )) && echo "errors present"(( code & 2 )) && echo "warnings present"Output formats
Section titled “Output formats”The local --output-format flag selects how results are rendered. It overrides the global --format for this command:
| Value | Output |
|---|---|
concise (default) |
Human-readable list, one finding per line, sorted by (file, line, column) |
json |
Compact structured result (diagnostics + summary) |
json-indent |
Same, pretty-printed |
sarif |
SARIF 2.1.0 log — for GitHub code scanning and other SARIF consumers |
github |
GitHub Actions workflow annotations (::error file=…) |
gitlab |
GitLab Code Quality report (JSON array) |
--output-file FILE writes the report to a file instead of stdout (for the json, json-indent, sarif, github and gitlab formats) — handy for uploading a CI artifact. A missing target directory yields a clear error rather than a traceback.
robotcode analyze code --output-format sarif --output-file reports/robotcode.sarifText output (concise)
Section titled “Text output (concise)”The default format prints one finding per line:
tests/login.robot:4:5: [ERROR] KeywordNotFound: No keyword with name 'Lgin User' found.tests/login.robot:7:1: [WARNING] KeywordNotUsed: Keyword 'Helper' is not used.Files: 12, Errors: 1, Warnings: 1, Infos: 0, Hints: 0 (in 0.42s)- Each line is
path:line:column: [SEVERITY] Code: message; the severity tag is colored (red/yellow/blue/cyan). - Output is sorted by
(file, line, column), so it's stable regardless of internal analysis order. - Workspace-level problems that aren't tied to a single file (e.g. a broken command-line variable file) are prefixed with
.:. - Related locations are shown on indented
->lines. - The summary line is colored after the highest severity present.
By default RobotCode trims the Python traceback and PYTHONPATH listing that Robot Framework appends to import errors. Pass --show-tracebacks to keep the full message.
--output-format sarif emits a SARIF 2.1.0 log — the format GitHub code scanning, Azure DevOps and the VS Code SARIF Viewer consume.
robotcode analyze code --output-format sarif --output-file robotcode.sarifPaths are written relative to the project root, which is what GitHub code scanning expects (use --full-paths for absolute paths). Once uploaded, an alert stays stable as long as the finding does — an unrelated edit that merely shifts its line number won't create a duplicate.
GitHub Actions annotations
Section titled “GitHub Actions annotations”--output-format github emits workflow annotations. Printed in a GitHub Actions job, they appear inline on the affected lines in the PR diff and in the run summary.
robotcode analyze code --output-format githubEach diagnostic becomes one annotation line:
::error file=tests/login.robot,line=4,endLine=4,col=5,endColumn=14,title=KeywordNotFound::No keyword with name 'Lgin User' found.GitLab Code Quality
Section titled “GitLab Code Quality”--output-format gitlab emits a Code Quality report that GitLab renders in the Merge Request Code Quality widget.
robotcode analyze code --output-format gitlab --output-file gl-code-quality.jsonEach diagnostic becomes one entry in the JSON array:
[ { "description": "No keyword with name 'Lgin User' found.", "check_name": "KeywordNotFound", "fingerprint": "…", "severity": "major", "location": { "path": "tests/login.robot", "lines": { "begin": 4 } } }]CI recipes
Section titled “CI recipes”GitHub: upload to code scanning
Section titled “GitHub: upload to code scanning”Produce a SARIF file and upload it so the findings appear under Security → Code scanning. The security-events: write permission is required for the upload, and continue-on-error lets the upload run even when analyze code exits non-zero because it found problems.
name: RobotCode Analyzeon: [push, pull_request]
jobs: analyze: runs-on: ubuntu-latest permissions: security-events: write # required for upload-sarif steps: - uses: actions/checkout@v5 - uses: actions/setup-python@v6 with: python-version: "3.x" # Set up the project with whatever package manager it uses (pip, uv, # poetry, pdm, hatch, ...); analysis just needs robotcode[analyze] available. - run: pip install robotcode[analyze] - run: robotcode analyze code --output-format sarif --output-file robotcode.sarif continue-on-error: true - uses: github/codeql-action/upload-sarif@v4 with: sarif_file: robotcode.sarifGitHub: inline PR annotations
Section titled “GitHub: inline PR annotations”Print the github format directly — the diagnostics show up as inline annotations on the run and in the PR diff. No upload and no extra permissions needed.
name: RobotCode Analyzeon: [push, pull_request]
jobs: analyze: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - uses: actions/setup-python@v6 with: python-version: "3.x" # Set up the project with whatever package manager it uses (pip, uv, # poetry, pdm, hatch, ...); analysis just needs robotcode[analyze] available. - run: pip install robotcode[analyze] - run: robotcode analyze code --output-format githubGitLab: Code Quality artifact
Section titled “GitLab: Code Quality artifact”Write the GitLab report and expose it as a codequality artifact; GitLab renders it in the Merge Request Code Quality widget.
robotcode-analyze: image: python:3 script: # set up the project with whatever package manager it uses (pip shown here) - pip install robotcode[analyze] - robotcode analyze code --output-format gitlab --output-file gl-code-quality.json artifacts: reports: codequality: gl-code-quality.jsonFail the build on errors only
Section titled “Fail the build on errors only”# Exit non-zero only for errors; warnings/infos/hints are reported but ignoredrobotcode analyze code --exit-code-mask warn,info,hintGet just the counts
Section titled “Get just the counts”robotcode analyze code --output-format json | jq '.summary'Managing the analysis cache
Section titled “Managing the analysis cache”To speed up repeat analysis, RobotCode caches resolved library/variable imports (and, unless you pass --no-cache-namespaces, analyzed namespaces) on disk. Library and variable file imports are cached per set of import arguments, so changing an import's arguments loads it again with the new ones. The analyze cache subcommands let you inspect and clear it:
robotcode analyze cache info # where the cache lives and how big it isrobotcode analyze cache list # what's cachedrobotcode analyze cache path # print the cache directoryrobotcode analyze cache clear # remove it (e.g. after changing ignored-libraries)robotcode analyze cache prune # delete the whole cache directory, for every Python/RF versionprune refuses while another process uses the cache; --force deletes it anyway.
The cache lives in a .robotcode_cache folder in the project root. cache-dir in the [tool.robotcode-analyze.cache] section of robot.toml moves it, for analyze and for the language server; for analyze, the ROBOTCODE_CACHE_DIR environment variable takes precedence.
Clearing the cache is the usual fix after changing cache-affecting settings such as ignore-arguments-for-library.
After each run, analyze code removes the entries of Robot Framework files that no longer exist, also of files outside the paths it analyzed. The language server removes them as soon as it notices that a file was deleted. The analysis of a file with a failed import is not cached, so a missing file or package is found once it is there. A cached analysis is not used either when an import of the file now finds another file or none, for example after a change of the Python path, or when an environment variable that the file uses without a default value has been set or unset since.
Configuration via robot.toml
Section titled “Configuration via robot.toml”Everything controllable on the command line (and more) lives under [tool.robotcode-analyze]:
[tool.robotcode-analyze]exclude-patterns = ["**/generated/**"]global-library-search-order = ["MyPreferredLibrary"]load-library-timeout = 30
[tool.robotcode-analyze.code]collect-unused = trueexit-code-mask = ["warn", "info", "hint"]
[tool.robotcode-analyze.modifiers]ignore = ["VariableNotFound"]error = ["MultipleKeywords"]
[tool.robotcode-analyze.cache]ignored-libraries = ["MyDynamicLibrary"]A library or variable file that takes longer than load-library-timeout seconds (default 10) to load is stopped, and its import reports the timeout (LibraryTimeoutError or VariablesTimeoutError). An import that ends before it finishes, for example through sys.exit(), reports LibraryExitError or VariablesExitError. RobotCode loads it again when a file in the library's directory, or the variable file itself, changes, or in a new session, for example after the language server restarts or on the next analyze code run.
See the robot.toml configuration reference for the complete list of settings.
JSON reference
Section titled “JSON reference”--output-format json (or json-indent) emits a single object with two keys, using the same LSP Diagnostic shape as robotcode discover:
{ "diagnostics": { "tests/login.robot": [ { "range": { "start": { "line": 3, "character": 4 }, "end": { "line": 3, "character": 13 } }, "message": "No keyword with name 'Lgin User' found.", "severity": 1, "code": "KeywordNotFound", "source": "robotcode" } ] }, "summary": { "files": 12, "errors": 1, "warnings": 0, "infos": 0, "hints": 0 }}Field notes:
- Keys in
diagnosticsare source paths (project-relative POSIX, or absolute with--full-paths). Workspace-level diagnostics key on.. severityfollows the LSP enum:1= Error,2= Warning,3= Information,4= Hint.- Positions are 0-based (LSP convention), unlike SARIF/GitHub which are 1-based.
- The JSON always carries the full diagnostic message —
--show-tracebacksdoes not apply. summaryis always present, even for a clean run (all counts0), so consumers get a stable schema.
Released under the Apache-2.0. Copyright © 2022-present Daniel Biehl