Parameter Validation
The Saner Python SDK includes a built-in parameter validation engine that verifies request inputs before sending them to the server. This ensures incorrect values are detected immediately and reported with clear, actionable error messages.
Instead of discovering mistakes after an API request fails, developers receive instant feedback directly in their scripts.
This validation layer is one of the key reliability features of the SDK.
Note: Parameter validation behaves identically across all three client classes (
SanerClient,PlatformClient,CvemClient); the examples below use flat resource access (client.Organization...,client.Device...) as ifclientis aPlatformClient/CvemClientscoped to that resource's product, since that's the shortest form. On aSanerClientinstance, prefix with the namespace instead:client.platform.Organization...,client.cvem.Device.... See the "Client Types" guide for the full comparison.
Why Parameter Validation Matters
Client-side validation provides several advantages:
- prevents invalid API calls from reaching the server
- reduces debugging time
- improves automation reliability
- detects integration mistakes early
- produces clear error messages explaining what went wrong
- eliminates unnecessary network requests
Example:
response = client.Organization.get(organization=123)Error raised:
TypeError: organization must be string; got 123 (int)The request never reaches the API server, saving time and avoiding runtime failures.
What an Error Message Tells You
Every validation error names three things where it can: the parameter, what was expected, and what was actually supplied. The trailing got ... clause is there so a correction never has to be re-derived, which matters most for the pattern rules, where the expectation alone is hard to act on:
ValueError: groupname has invalid format (expected ^[A-Za-z0-9._\- ]+$); got 'dev team!'
TypeError: port must be string; got 8080 (int)For a list parameter the clause is reported against the failing element, so emails[1] must be string; got 123 (int) points at the one entry to fix.
Three deliberate exceptions:
- Secret parameters are never echoed. Any parameter whose name marks it a credential (
password,proxypassword, and anything matching the same stems) reports only the rule it broke, never the value. A validation error is what ends up in your own logging stack, sopassword must contain at least one digitis all you get. - Email addresses are not echoed either, since the value is personal data and the expected format is already stated.
- Length rules report the length, not the value:
username must be <= 50 characters (got 63).
Echoed values are truncated at 2048 characters, so a large payload cannot bloat the message.
Discover Parameter Types Directly in Your IDE
The Saner SDK provides rich inline docstrings that allow developers to view parameter requirements directly inside their IDE.
When hovering over a method or its parameters, you can instantly see:
- parameter type requirements
- required vs optional parameters
- allowed enum values
- formatting expectations
- usage notes
Example:
client.Organization.get(organization="ExampleOrg")Hovering over:
organizationwill display its expected type and description inside your editor.
This enables developers to identify correct parameter formats without switching to external documentation.
For more details, see the "IDE Docstring Support" guide.
Mandatory Field Validation
Required parameters are enforced automatically.
If a required parameter is missing or empty, the SDK raises an exception immediately.
Example:
response = client.Organization.remove(name="")Error:
ValueError: name cannot be emptyThis prevents incomplete payloads from being sent to the API server.
At Least One Of (Grouped Requirements)
Some endpoints have no single mandatory parameter, but do require at least one of a group. Device.scan is the clearest example: it accepts a hostname, an IP address, or a MAC address, and needs at least one of them to know which device to scan.
The SDK enforces the group as a whole, so calling such a method with none of its alternatives fails before a request is sent.
Example:
response = client.Device.scan()Error:
ValueError: ScanDeviceModel requires at least one of: hostname, ip, mac. The server answers a request carrying none of them with HTTP 200 and a FAIL body, so it is rejected here rather than sent.Supplying any one of them satisfies the rule:
response = client.Device.scan(hostname="workstation-01")This check is worth more than it first appears. The Saner API answers a request carrying no device identifier with HTTP 200 and a FAIL status inside the body, which reads like an empty result set rather than a rejection. Validating the group locally turns that into an immediate, explicit error instead.
Two details worth knowing:
- An empty string does not satisfy the rule.
client.Device.scan(hostname="")behaves the same as passing nothing at all, because an empty optional value is dropped before the payload is built. - A malformed value reports its own error first.
client.Device.scan(ip="not-an-ip")raisesValueError: ip must be valid IPv4 address; got 'not-an-ip', not the group error, so you always see the more specific problem.
Methods documented to return everything when called without a filter, such as Account.get and Organization.get, are unaffected and still accept an empty call.
Type Validation
Each parameter is validated against its expected type before execution.
Supported validations include:
- string values
- integers
list[str]list[dict]dict[str, str]- structured JSON payloads
Example:
response = client.Organization.get(organization=123)Error:
TypeError: organization must be string; got 123 (int)This ensures the request matches the expected API schema exactly.
Enum Validation (Allowed Values Only)
Parameters restricted to predefined values are validated automatically.
Example validator definition:
role = Field(required=True, enum=["ADMIN", "ORGADMIN", "ACCOUNTADMIN", "NORMAL"])Valid usage:
role="ORGADMIN"Invalid usage:
role="SUPERADMIN"Error:
ValueError: role must be one of ['ADMIN', 'ORGADMIN', 'ACCOUNTADMIN', 'NORMAL']; got 'SUPERADMIN'This prevents unsupported configuration values from reaching the API server. Every enum parameter lists its accepted values in the method docstring, so check there rather than guessing.
Format Validation
Structured formats are validated automatically.
Supported formats include:
| Format | Example |
|---|---|
[email protected] | |
| IPv4 | 192.168.1.10 |
| MAC address | AA-BB-CC-DD-EE-FF |
| date | 2026-04-01 |
| numeric string | "12345" |
| float string | "12.34" |
| boolean string | "true", "false" |
| numeric list | "1", "1,2", "8,9,10" |
| time of day | 03:30:PM, 18:30:00 |
| date and time | 2023-09-25.18:00:00, 2023-09-25 18:00:00 |
Example:
email="admin.example.com"Error:
ValueError: email must be a valid emailEvery format rule matches the entire value, not just a leading portion, so a value that looks valid at the start but carries something extra is rejected rather than silently truncated to its valid-looking prefix:
email="[email protected]<newline>Bcc: [email protected]"
email="[email protected], [email protected]"Both raise ValueError: email must be a valid email. Control characters and embedded whitespace are rejected outright, since a value like the first example is designed to smuggle extra content into a field the server later treats as an email header.
IPv4 validation is similarly strict about ambiguous input:
ip="010.0.0.1"ValueError: ip must be valid IPv4 address; got '010.0.0.1'A leading zero is rejected rather than silently interpreted as decimal: some resolvers read 010 as octal (8), so accepting it would let the same string mean two different addresses depending on what parses it downstream.
This ensures parameters follow correct formatting before transmission.
Date and Time Formats
Scheduling parameters (starttime, startwindowtime, endtime, autoreboottime, rebootdatetime, schedule, schedulevalue) are validated against the format the API documents for them. Before this, a wrong-format time was the one mistake that had to reach the server to be caught:
client.Patch.createRemediationJob(..., starttime="9am")ValueError: starttime has invalid format (expected ^(([01]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]|([01]?[0-9]|2[0-3]):[0-5][0-9]:(?i:AM|PM))$); got '9am'Each method's docstring states the format that method's parameter expects, so check there first. The shapes in use are:
| Shape | Example | Used by |
|---|---|---|
HH:MM:AM/PM | 03:30:PM | starttime, startwindowtime, endtime on most methods |
HH:MM:SS | 18:30:00 | starttime and endtime on Compliance.createMisconfigurationRollbackTask |
YYYY-MM-DD.HH:MM:SS | 2023-09-25.18:00:00 | autoreboottime (note the dot) |
YYYY-MM-DD HH:MM:SS | 2023-09-25 18:00:00 | rebootdatetime on the Endpoint deployment and uninstall methods (note the space) |
YYYY-MM-DD | 2024-12-29 | schedule, schedulevalue |
YYYY-MM-DD or immediate | immediate | schedule on the Patch job-creation methods |
Two notes on how strict this is:
- Both time shapes are accepted wherever a time of day is expected. The API documentation is not consistent about which of the two a given parameter takes, so both pass validation and the server decides. Follow the docstring for the method you are calling; the pattern only rejects shapes that are documented nowhere, such as
"9am","09:00 AM"(a space rather than the API's colon) or a bare"21:00". rebootdatetimeaccepts either separator, a space or a dot, because the API reference documents2019-06-29 00:00:00forEndpoint.addSoftwareDeploymentand2019-06-29.00:00:00forEndpoint.uninstallSoftware.autoreboottimeis documented consistently with a dot and only accepts that.
Reboot Flags and Schedule Components
forcereboot and autoreboot accept "TRUE" or "FALSE" in either case, since the API reference documents both spellings, sometimes within a single method:
forcereboot="TRUE" # accepted
forcereboot="false" # also accepted
forcereboot="yes" # rejectedThe schedule component parameters (monthoftheyear, weekofthemonth, dayoftheweek, dayofthemonth) each accept one or more comma-separated numbers, not a single number:
weekofthemonth="1" # accepted
dayoftheweek="3,6" # accepted
monthoftheyear="8,9,10" # accepted
dayoftheweek="mon" # rejectedLength Validation
Parameters with length constraints are validated automatically.
Example validator definition:
username = Field(min_length=5, max_length=50)Invalid usage:
username="abc"Error:
ValueError: username must be at least 5 characters (got 3)Another example:
username="a" * 100Error:
ValueError: username must be <= 50 characters (got 63)Boolean String Validation
Some API parameters accept boolean values as strings, spelled in lowercase.
Example:
hostpeerverification="yes"Error:
ValueError: hostpeerverification must be either true or false; got 'yes'Correct usage:
hostpeerverification="true"This rule is strict about case, which is right for the parameters the API documents only in lowercase (hostpeerverification, usecredential, secureldap, bufferpatchesenabled). It is deliberately not used for forcereboot and autoreboot, which the API documents in both cases: see the "Reboot Flags and Schedule Components" section above. Note also that a yes/no parameter such as sslverify is an enum of "yes"/"no", not a boolean string.
Password Strength Validation
Credential parameters enforce strong password rules automatically.
Requirements include:
- minimum 8 characters
- maximum 100 characters
- at least one digit
- at least one uppercase character
- at least one lowercase character
- at least one special character
Example:
password="weakpass"Error:
ValueError: password must contain a special characterThis helps enforce secure integrations by default.
List Validation
List-based parameters are validated element-by-element.
Example:
emails=["[email protected]", 123]Error:
ValueError: emails[1] must be string; got 123 (int)Supported list validation types:
list[str]list[email]list[dict]
Combining List Validation with Format and Length Rules
A list[str] parameter can also carry the same format and length rules used for a single string: each rule is then applied to every element of the list, and a failure is reported with its index.
Example validator definition:
groupname = Field(
required=True,
list_string=True,
max_length=50,
regex=r"^[A-Za-z0-9._\- ]+$",
)Valid usage:
groupname=["prod-servers", "db.cluster"]Invalid usage, with one entry exceeding the length limit:
groupname=["prod-servers", "x" * 100]Error:
ValueError: groupname[1] must be <= 50 characters (got 100)Invalid usage, with one entry failing the pattern:
groupname=["../../etc/passwd"]Error:
ValueError: groupname[0] has invalid format (expected ^[A-Za-z0-9._\- ]+$); got '../../etc/passwd'This applies to any scalar rule (max_length, min_length, regex, email, enum, date, and similar) whenever it is combined with list_string=True.
IPv4 and MAC Address Validation
Network-related parameters are validated for correctness.
Example:
ip="192.168.1.999"Error:
ValueError: ip must be valid IPv4 address; got '192.168.1.999'Example:
mac="invalid-mac"Error:
ValueError: mac must be valid MAC address; got 'invalid-mac'JSON Payload Validation
Structured JSON inputs must be valid dictionaries or lists.
Example:
payload="invalid"Error:
TypeError: payload must be valid JSON object (dict or list); got 'invalid'Example Validation Flow
When calling any SDK method, validation occurs in the following order:
Step 1 → required field validation
Step 2 → type validation
Step 3 → format validation
Step 4 → enum validation
Step 5 → length validation
Step 6 → request executionIf any validation step fails, execution stops immediately with a clear error message.
Benefits for Developers
The validation system improves integration quality by:
- catching mistakes instantly
- preventing malformed API requests
- reducing debugging cycles
- providing human-readable error messages
- enforcing correct parameter usage
- improving production automation stability
These safeguards make the Saner Python SDK safer and easier to use across both small scripts and enterprise-scale automation workflows.
Updated 10 days ago