Release Notes¶
Upcoming Qiskit Serverless release¶
New Features¶
BackgroundExecutor.submitaccepts an optionalreplace_key: a task that is still waiting with the same key in the same pool is replaced by the new one, which takes its place in the queue and needs no new slot. There is a new outcomereplacedinbackground_executor_tasks_total, andBackgroundExecutor.would_accepttells whether asubmitwould be accepted. The outcomeskippedof that metric is now calledcanceled.
The backoffice “Stop job” button now works on a Fleets job. It cancels the job’s Code Engine fleet and records
STOPPING, and the scheduler confirms the stop like any other. Before, the button was only shown for Ray jobs, so a Fleets job could not be stopped from the backoffice at all. The job is billed for what it really ran, the same as a stop from the client.
BackgroundExecutor.discard(pool, replace_key)removes a task that is still waiting in the queue under thatreplace_key, so a result that is no longer needed does not take a thread. A task that already started is never touched. The discarded task is counted ascanceled.
The scheduler no longer submits a queued Fleets job whose account, plan and subscription are blocked. The job stays
QUEUEDand does not take a free slot from other users, and it is submitted normally once the block is lifted.
GET /api/v1/jobs/{id}/now returns a short-lived job status token in theX-Job-Status-Tokenheader, to the author of a job that has not ended. The newGET /api/v1/jobs/{id}/status/accepts only that token, and returns the jobstatus,sub_statusandfleet_idfrom two small database reads, with no IBM Cloud call. The token is valid for 5 minutes.
status()andwait_for_final_state()now use the job status token when the gateway returns one. So most status checks no longer send the API key. The client goes back to the API key when the token is older than 4 minutes and 30 seconds, or when the gateway refuses it. With an older gateway nothing changes.
Added
wait_for_final_state(), which waits until a job isDONE,ERRORorCANCELEDand returns that status:job.wait_for_final_state(timeout=600) # 'DONE'
It checks the status after 1, 2, 4, 8, 16 and 32 seconds, then every 60 seconds, and starts again from 1 second when the main status changes or the job enters post-processing. So a short job is seen within seconds, and a long job makes fewer requests than a loop that checks every few seconds. If the status does not change for a while, the end can be seen up to about 60 seconds late.
poll_intervalsets a fixed interval instead, of at least 1 second.A
timeoutraisesTimeoutErrorand never cancels the job. Short network errors and429,502,503or504answers are retried at the same pace, until the timeout, or for up to 5 minutes in a row when there is no timeout. Any other error, or one that lasts that long, is raised.verbose=Trueprints one line per status change and per retried error, and the error message if the job ends inERROR.
status()now asks the service only until the job reachesDONE,ERRORorCANCELED, and then returns that status without a request, because a final status cannot change. So callingresult()orerror_message()on a finished job no longer sends the same status request again and again.
Fleets jobs can now be mirrored to the Runtime API as workloads. While the
workloads.mirror.enabledsetting is on (it is off by default), each new Fleets job that has an instance CRN is sent to the Runtime API when it is created, and its final status is sent when it ends. A job created before the setting was turned on is not mirrored, and turning the setting off does not stop the jobs already mirrored from reporting their final status. Inside the container of a mirrored job, the environment variableQISKIT_FUNCTIONS_IDENTIFIERholds the job id. Instead oftruethe setting can be a comma separated list of providers (qctrl), functions (qctrl/management) andcustom(functions without a provider), and only the jobs of those are mirrored.
The scheduler exports three new metrics:
scheduler_code_engine_request_duration_secondsby endpoint and status,scheduler_cos_request_duration_secondsby operation and status, andscheduler_fleets_breaker_openby dependency and region. A Code Engine 429 shows up as astatus="429"series. The gateway does not record them.
The scheduler exposes
scheduler_loop_duration_max_secondsandscheduler_task_duration_max_seconds(per task): the longest duration among the loops and tasks that ended in the last 120 seconds, so one very slow loop can be read in Grafana without averaging. A loop that is still running does not show up until it ends.
The scheduler now records how long it takes to submit one Fleets job, as the new
fleet_submitoperation ofscheduler_operation_duration_seconds. It covers the whole submit, from the Code Engine request to the job reachingPENDING, and records one sample per attempt, failed ones included, with statusok,timeoutorerror.
The
scheduler_operation_duration_secondshistogram has new operations that time the job status transitions the scheduler makes, wherever they are called from:job_transition_queued_to_pending,job_transition_pending_to_runningandjob_transition_to_terminal. The last one also counts the jobs that end because they are filler jobs or because their fleet is blocked, not only the ones thatUpdateFleetsJobsStatusesfinishes.job_transition_pending_to_runningincludes thejob_startedevent sent right after the transaction, so it is not database time alone. Another new operation isjob_in_progress_event(the progress event sent for a job that is still running, not a transition, and never for a filler job). Together withfleet_status_readthey show how much ofUpdateFleetsJobsStatusesis database and how much is Cloud Object Storage. A transition rejected because the job was already moved by someone else (a user stopped it) is recorded with the statusrejectedand noterror.job_transition_to_terminalcovers a job that succeeds, fails or is stopped byto_stopped, but not the status written bystop()(the stop of a job by a user or by the timeout), which also cancels the fleet in Code Engine. The gateway records nothing.
The scheduler now cancels the
PENDINGandRUNNINGFleets jobs whose account, plan and subscription are blocked, so a resource whose non-quantum allowance is exhausted stops consuming Code Engine capacity. The job goes throughSTOPPINGlike any other stop and is billed for what it really ran. Thescheduler.blocked_jobs_stop.enabledconfiguration turns this off at runtime without a deploy.
Upgrade Notes¶
qiskit-paulice==0.2.1has been added to the dynamic dependencies allowlist bundled in the custom functions image. Qiskit Functions that declare it as a dependency can now use it.
A stop from the backoffice no longer writes
STOPPEDon the job row by hand. It goes through the same transition service as every other stop, so an operator sees an error instead of a silent write when Code Engine cannot be reached. The Qiskit Runtime jobs a job started are not cancelled from the backoffice: that needs the caller’s own service credentials.
The
api_job.compute_profiledatabase column has been dropped, along with its historical data. The gateway stopped reading and writing it in 0.37.0 and reads the compute profile fromJob.compute_profile_fkinstead.Gateway releases before 0.37.0 can no longer be deployed against a database that has run this migration, because their
Jobmodel still declares the column. Upgrade to 0.37.0 before upgrading to this release.
Migration
0078fillsfunction_size_namefor existing jobs with the current label of their size row. A row renamed before the upgrade gives its new label, because the old one was never stored. Jobs whose row was already deleted stay without a size.
While
workloads.mirror.enabledis on, running a Fleets function with an instance CRN can fail with a503error, and no job is created, if the Runtime API does not accept the job. Retrying the request later is safe.
scheduler_loop_duration_secondsandscheduler_task_duration_secondsnow have buckets up to 30 minutes. The old buckets stopped at 10 seconds.
scheduler_loop_duration_secondsandscheduler_task_duration_secondshave three more buckets, 3600, 7200 and 14400 seconds.
Security Issues¶
A job status token lets its holder read the status of one job for up to 5 minutes, even if the API key is revoked in that time. It only gives the status, sub-status and fleet id of a job the user authored. A deactivated user cannot use it.
Bug Fixes¶
The gateway and the scheduler now reuse a Code Engine Fleets project’s COS client for 60 seconds. Before, every status poll of every running job and every COS request made its own Code Engine call to read the COS HMAC secret, so a busy scheduler could reach the Code Engine API rate limit by itself. A rotated HMAC secret is picked up within 60 seconds.
A request that reads or writes a Code Engine Fleets job’s files in COS now answers 503 “please retry” when Code Engine rate limits the gateway, answers a 5xx, or does not answer in time. It used to answer 500. This covers running a function, and reading its logs, result and files. Reading the COS HMAC secret from Code Engine now has a request timeout, so such a request no longer hangs.
A failed request for an IAM token that the caller retries is now logged as a warning instead of an error. The wait for IAM is 3 seconds to connect and 5 seconds to read, as it was for Code Engine and COS before they shared the IAM token provider, instead of 3 seconds for both. A rejected API key is still logged as an error.
A Fleets job now keeps the size it ran with. The new
Job.function_size_namecolumn stores the size label when the job is created, and the license fee, the Runtime API mirror payload,ENV_JOB_FUNCTION_SIZEand the admin job pages read it instead of theJob.function_sizerow. Before, renaming that row in the backoffice, or deleting it by re-uploading the function with a different sizes map, changed the size of every job still running with it, so the license fee was charged at the new size’s rate or waived.Job.function_sizeis kept as a link to the catalog row.
The scheduler now measures the duration of its loop, its tasks and its internal waits with a monotonic clock instead of the wall clock, so a clock adjustment (NTP correction, VM pause) can no longer show up as a very long loop or task in the scheduler metrics. The
scheduler_start_timestamp_secondsandscheduler_last_tick_timestamp_secondsmetrics stay on the wall clock.
Authentication now writes only the user’s groups that changed, so a request whose groups did not change makes no database write. This also removes a short window in which a parallel request from the same user could see no groups.
The authentication errors that asked users to try again later, where retrying alone cannot help, now say what to check first, or to contact IBM support.
Other Notes¶
The scheduler now exposes
scheduler_operation_duration_seconds, a histogram of how long it takes to read the status of a Fleets job, to upload the files of a job when submitting it, to request an IAM token and to send a workload to the Runtime API. It is labeled by operation and by status: ok, timeout or error, or the HTTP code for the Runtime API call. Only the requests that really reach IAM are timed, not the ones answered from the token cache. The gateway does not record it.
The IAM token used for Cloud Object Storage and the Runtime API is now renewed in a background thread when less than 40% of its life, or 10 minutes, is left, so a request no longer waits for the renewal.
The scheduler now exposes
scheduler_task_items_total(jobs submitted and jobs whose status was checked, per task),scheduler_fleets_jobs_skipped_by_breaker_total(jobs a Code Engine circuit breaker kept queued, per region) andscheduler_process_threads(live threads of the process).
GET /api/v1/jobs/{id}/now reads the job, its program, its provider and its compute profile in one database query.
v0.37.0¶
Prelude¶
qiskit_serverless v0.37.0 tightens circuit serialization: the gateway now injects an authoritative Qiskit configuration into every job and enforces a minimum QPY version of 13 (Qiskit 1.3.0), so circuits serialized with an older Qiskit are rejected at load time. Cancelling a job now reports a new STOPPING status until the compute is actually released, instead of being reported as stopped straight away. The deprecated compute_profile input on run() is removed in favour of function_size, whose label is restricted to S, M, L and XL. This release also adds a provider filter to function listing, bundles the CUDA runtime libraries and qiskit-fermions for GPU chemistry in the custom functions image, and raises the required qiskit-ibm-runtime version to 0.50. Finally, it removes the Ray-coupling client helpers that were deprecated in 0.34.0 (the distribute_task decorator, the get, put and get_refs_by_status helpers, distribute_qiskit_function and qiskit_serverless.core.remote); functions that need in-function parallelism should use Ray directly.
New Features¶
Running Qiskit Functions can now read the compute sizing their job resolved to, with two new helpers,
get_function_size()andget_compute_profile():from qiskit_serverless import get_function_size, get_compute_profile get_function_size() # e.g. "M" get_compute_profile() # e.g. "24x120x1a100p"
This lets a function check which
function_sizethe user submitted and which compute profile it mapped to. Both are always set for Fleets jobs (the requested size, or the function’s default when none was requested) and are empty when sizes do not apply, i.e. a non-Fleets (Ray) job. The values are set by the gateway at job submission through theENV_JOB_FUNCTION_SIZEandENV_JOB_COMPUTE_PROFILEenvironment variables.
qiskit-fermions==0.2.0has been added to the dynamic dependencies allowlist bundled in the custom functions image. Qiskit Functions that declare it as a dependency can now use it.
The custom functions image now ships the CUDA runtime libraries
gpu4pyscfneeds at import, so GPU chemistry functions no longer have to install those wheels themselves.
The gateway now injects an authoritative Qiskit user configuration file (
settings.conf) into every Ray and Code Engine Fleets job container and pointsQISKIT_SETTINGSat it. The file currently sets a single key,min_qpy_version(default13, configurable fleet-wide with theQISKIT_MIN_QPY_VERSIONenvironment variable), which makes Qiskit reject QPY payloads older than that version. For Fleets the file is written by the job wrapper at container startup; for Ray it is written into the job working directory and referenced by a cwd-relativeQISKIT_SETTINGS.
Listing Qiskit Functions now accepts a
providerargument that returns only the functions belonging to that provider:client.functions(provider="q-ctrl")
The filter narrows the functions the caller can already see, so it never widens access, and a provider the caller has no functions under returns an empty list.
Cancelling a job now reports a new
STOPPINGstatus, shown by the client SDK asCANCELING, until the job has really stopped and its compute is released. Previously the job was reported as stopped straight away, while its compute was still being released. Sub-status and error reporting keep working while a job is stopping.
Upgrade Notes¶
Qiskit Serverless now requires
qiskit-ibm-runtime==0.50, raised from0.49.
The optional
rayextra (pip install qiskit-serverless[ray]) now requiresray>=2.59, raised from2.58.
Several packages have been added to the dynamic dependencies allowlist bundled in the custom functions image:
h5py,mpi4py,openmpi,pybind11andqrmi[ibm]. Qiskit Functions that declare any of them as a dependency can now use them.ffsimis updated to0.0.70andqiskit-addon-sqdto0.13.1.
qiskit-fermions==0.2.0requiresqiskit~=2.5.0, so theqiskitversion in the custom functions image is now held to the 2.5 line. Functions that relied on an earlierqiskitin the image should review the Qiskit 2.3-2.5 release notes for API changes.
The gateway-provided
settings.confis authoritative: a function’s own Qiskit configuration file is no longer consulted in the Functions runtime. Qiskit reads exactly the one fileQISKIT_SETTINGSnames, with no merging, and the gateway setsQISKIT_SETTINGSin the system-controlled environment layer that overrides any value a function supplies. A function that shipped or wrote its ownsettings.conf(at the default~/.qiskit/settings.confor elsewhere) will find it ignored. Function vendors that need Qiskit configuration beyondmin_qpy_versionmust apply it programmatically in their function code rather than through a configuration file.
The
distribute_taskdecorator and theget,putandget_refs_by_statushelpers have been removed. They were deprecated in 0.34.0 as thin wrappers around Ray’s native API, which must now be used directly. Functions that need in-function parallelism shouldimport rayand use Ray’s own decorators:distribute_task-> ray.remoteget-> ray.getput-> ray.putget_refs_by_status-> ray.wait
Before (using the removed Qiskit Serverless wrappers):
from qiskit_serverless import get_arguments, save_result, distribute_task, get @distribute_task() def distributed_transpilation(circuit, target_backend): ... # returns an ISA circuit return isa_circuit refs = [distributed_transpilation(circuit, backend) for circuit in circuits] isa_circuits = get(refs) save_result({"results": isa_circuits})
After (using Ray directly):
import ray from qiskit_serverless import get_arguments, save_result @ray.remote def distributed_transpilation(circuit, target_backend): ... # returns an ISA circuit return isa_circuit refs = [distributed_transpilation.remote(circuit, backend) for circuit in circuits] isa_circuits = ray.get(refs) save_result({"results": isa_circuits})
The
distribute_qiskit_functiondecorator has been removed. It was deprecated in 0.30. Use theuploadfunctionality ofServerlessClientinstead.
qiskit_serverless.core.remote, a thin proxy around ray.remote, has been removed. Useray.remotedirectly, as shown above.
The OpenTelemetry spans that
distribute_taskinjected around each distributed task have been removed along with it, including the per-taskqs.meta.*,qs.resources.*,qs.args.*andqs.kwargs.*span attributes. The client-sidejob.*,function.*andfiles.*spans, and gateway and scheduler tracing, are unaffected.
The deprecated
compute_profileinput onPOST /programs/run/has been removed. Usefunction_sizewith one of the labels the function declares instead. Sendingcompute_profilenow returns a 400 naming the replacement, instead of being silently ignored.The client SDK’s
compute_profilekeyword onrun()now raisesQiskitServerlessExceptionlocally instead of sending the request, so upgrade the client to get a clear error rather than a generic 400 from the gateway.
The size label declared for a function is now restricted to
S,M,LandXL. A size outside this catalog is rejected on/programs/upload. A size is accepted case-insensitively and stored and read back in uppercase.
A cancelled job stays in
STOPPINGuntil its compute is released, and counts against the user’s active and running job limits for that time. A cancellation that is never confirmed is forced to stopped after 5 minutes.
Stopping a job now answers “Serverless job stop has been requested.” where it used to say the job “was running and has been stopped”, since the request only asks for the stop and does not wait for it to finish.
Security Issues¶
The
custom_tokenauthentication mechanism no longer accepts thelocalchannel, which checks a static mock token and needs no instance. The Helm chart also stops passingSETTINGS_AUTH_MOCK_TOKENto the pods unless the mechanism ismock_token.
Bug Fixes¶
A request whose authentication could not be completed because IBM Cloud was unreachable, timed out, or returned a server error now fails with
HTTP 503and a message asking the user to retry, instead of a401telling them to review their API key or CRN. Valid credentials and a valid CRN are no longer reported as invalid during an IBM Cloud outage; the401messages are kept only when IBM Cloud actually rejects the API key or the CRN.
A request that fails to reach the service because the connection was dropped, the TLS handshake failed, or the request timed out now raises a
QiskitServerlessExceptionwith codeCONN1001and a message saying the failure is usually temporary and to try again. These transient failures were previously reported with codeAUTH1001and a message telling the user to check their host and authentication, which pointed at configuration that was not the problem.
A successful response that arrives with an empty body, which happens on a transient blip and clears on retry, now raises a
QiskitServerlessExceptionwith codeEMPTY1001and a message saying to try again. It was previously reported with codeJSON1001as a server json decoding error, which read as a permanent problem.
The gateway and the scheduler now exit when their startup migration fails, instead of starting against a database that does not match the code.
Fixed GPU chemistry functions silently running on the CPU, because the CUDA libraries
gpu4pyscfloads at import were missing from the image. The image now installs them and its build checks that they resolve.
A request to the IBM Cloud and IBM Quantum Platform channels without the
Service-CRNheader now fails with an authentication error that asks for the header, instead of an internal server error.
v0.36.0¶
Prelude¶
qiskit_serverless v0.36.0 updates the pinned qiskit-ibm-runtime requirement to 0.49.0 and refreshes the client, gateway and test dependency groups. The rest of the release is internal platform work and is not part of the public surface; upgrading is optional for users of the Python client.
Upgrade Notes¶
qiskit-ibm-runtimeis now required at0.49.0(raised from0.47.0). Environments that pin the client’s transitive dependencies should widen the constraint accordingly.
v0.35.1¶
Prelude¶
qiskit_serverless v0.35.1 is a bug-fix release with a few improvements over v0.35.0; upgrading is advised but not required. GET /api/v1/jobs/provider now scopes its results to the requested provider, running a Qiskit Function with a large batch of arguments no longer fails with a 500 error, and get_runtime_service() is now compatible with VPE configurations. The author of a provider function is also now treated as an admin of that function for the provider operations, so an automated publisher can manage the functions it uploads.
Upgrade Notes¶
Two new settings, both also exposed as chart values under
gateway.application.limits:MAX_REQUEST_BODY_SIZE_MB(maxRequestBodySizeMb, 50) andMAX_ARGUMENTS_LENGTH_MB(maxArgumentsLengthMb, 32). Size them against the pod’s memory and worker count, since a body costs about three times its size in the worker holding it and every worker can hold one at once.specs/ARGUMENTS_LIMIT.mdhas the table.
The author of a provider function is now treated as an admin of that one function for the six provider operations: uploading a new version, listing the function’s jobs, reading its provider logs, and the three provider file operations. This lets an automated publisher manage the functions it uploads without extra grants.
The grant is scoped to that single function. It does not list the function in the catalog, does not grant the right to run it, and does not make the author an admin of the provider as a whole. Creating a brand-new provider function still requires the upload permission, and access that worked before is unaffected.
Bug Fixes¶
Running a Qiskit Function with a large batch of arguments no longer fails with
500 Internal server error. The gateway now accepts request bodies of up to 50 MB, and reports going over that as413 Request Entity Too Largenaming the limit.
Raised the maximum length of the arguments validated against a function’s
arguments_schemafrom 1 MB to 32 MB. The old figure fit only about twenty-five encoded circuits, fewer than callers send in a single batch.
get_runtime_service()now honours theQISKIT_IBM_PRIVATE_ENDPOINTenvironment variable, forwarding it toQiskitRuntimeServiceasprivate_endpoint. Previously the helper ignored it, so a Qiskit Function configured for a private endpoint still connected through public URLs. Set it totrueand the service connects through private URLs; the instance must be a CRN for the private host to resolve. Existing usage is unchanged.Example usage from within a Qiskit Function, with the variable set in the environment:
from qiskit_serverless import get_runtime_service service = get_runtime_service() backend = service.backend("my_backend")
GET /api/v1/jobs/providernow scopes its results to the requested provider. Because function titles are unique per provider rather than globally, a title alone could match same-named functions under other providers, so the listing could include jobs outside the requested provider. It now returns only jobs belonging to that provider. The response carries job metadata only (id, status, timestamps and the function’s id, title and provider); retrieving a job, its results or its provider logs is authorized separately against the job’s own provider and is unchanged.
GET /api/v1/jobs?filter=catalog&provider=<name>no longer returns500 Internal server errorwhen the provider is given by name.
v0.35.0¶
Prelude¶
qiskit_serverless v0.35.0 is a feature release that adds argument validation for Qiskit Functions: functions can now declare a JSON Schema for their arguments and the gateway validates submissions before any compute is used, with a new validate_arguments client method for pre-flight checks. The QiskitFunction.schema field has been renamed to arguments_schema. This release also removes the deprecated name parameter from ServerlessClient and bumps the ray-node default Python version to 3.12.
New Features¶
Qiskit Functions can now declare the arguments they accept as a JSON Schema, and the gateway validates submitted arguments against it before any compute is used. Previously a function given bad input failed mid-execution, after the user had already waited through queue time and container startup.
Attach the schema when uploading a function through the
arguments_schemafield ofQiskitFunction:function = QiskitFunction( title="my-function", entrypoint="main.py", working_dir="./src", arguments_schema={ "type": "object", "required": ["shots"], "properties": {"shots": {"type": "integer"}}, }, ) runnable = client.upload(function)
From then on, running that function with arguments that do not match the schema is rejected with a
400before the job is created, so no job is queued and no partial rows are left behind. The error names the keyword that failed, what the schema asked for, and the value that was rejected, andpathpoints at the offending field:{ "message": "'type' validation failed, schema requires 'integer': rejected value 'wrong-type'", "path": ["shots"] }
The feature is opt-in and backwards compatible: functions without a schema are never validated.
Re-uploading a function without the field keeps the schema it already had, so a schema is removed by uploading an empty one:
function.arguments_schema = {} client.upload(function)
Two things to know when writing a schema. First, the schema is applied to the arguments as the SDK encodes them, not as they look in Python, so a
QuantumCircuitarrives as{"__type__": "QuantumCircuit", "__value__": "<base64 QPY>"}and a numpy array as an object rather than an array. Describing a circuit or an array argument with{"type": "array"}therefore rejects every legitimate call. The advice is to constrain the plain arguments (counts, names, options, flags) and to check only the__type__tag of the Qiskit ones.
New endpoint
POST /api/v1/programs/validate_arguments/checks arguments against a function’s schema without submitting a run, so inputs can be verified before paying for a job. It resolves the function with the same permission rules as/runand returns200 {"valid": true}or a400describing the problem.From the client SDK:
runnable.validate_arguments({"shots": 1024})
Invalid arguments raise
QiskitServerlessException.
Functions read back with
client.function(...)orclient.functions()now includearguments_schema, so the arguments a function expects can be inspected even by callers who did not upload it.
Upgrade Notes¶
QiskitFunction.schemahas been renamed toarguments_schemaand its type changed fromOptional[str]toOptional[Union[Dict[str, Any], bool]]. The old field was never read by the client nor sent to the gateway, so there is no deprecation path. Pass a plain dict rather than a JSON string. A boolean is accepted becausetrueandfalseare valid JSON Schemas in their own right, accepting and rejecting every argument respectively.
The unused
validatefield has been removed fromQiskitFunction. It gated a client-side validation hook that was never implemented and always reported success, so passingvalidate=Falsehad no effect. Argument validation now happens on the gateway againstarguments_schema.
The supported range for
qiskit-ibm-runtimehas been updated to>=0.47.0, <0.50.0.
The default Python version in the
ray-nodeimage has been bumped from 3.11 to 3.12. The Dockerfile now usesARG PYTHON_VERSION=3.12so the version can still be overridden at build time if needed.
The Apple Silicon local-development image is no longer a separate
ray-node/Dockerfile.arm64file. It is now thearm64stage ofray-node/Dockerfileand is built with--target arm64 --platform linux/arm64. Thedocker-compose-dev.arm64.yamloverride has been updated accordingly; no changes are needed to existing local-dev workflows beyond rebuilding the image.
The
nameattribute has been removed fromServerlessClientandBaseClient. This parameter was deprecated in v0.33.0 and emitted aDeprecationWarning; it is now fully removed. Passingnamewhen constructing a client will raise aTypeError.Migration guide
Remove the
nameargument from anyServerlessClient(orBaseClient) construction. It was never used for authentication or routing, so it can be deleted without any replacement.Before:
client = ServerlessClient( name="my-client", host="<HOST>", token="<TOKEN>", instance="<CRN>", )
After:
client = ServerlessClient( host="<HOST>", token="<TOKEN>", instance="<CRN>", )
Additional notes for existing code:
ServerlessClient.from_dict(...)continues to accept dictionaries that still contain anamekey; the key is silently ignored, so previously serialized clients keep deserializing without changes.BaseClient.__eq__now compares clients by theirhost,token,instance, andchannelinstead of byname. Code that relied on name-based equality should compare the relevant connection attributes directly.repr(client)now renders as<ServerlessClient(host=<HOST>)>instead of<my-client>. Update any code or tests that matched the old representation.The
nameattribute onIBMServerlessClient(used to select a saved account) is unaffected by this change.
Bug Fixes¶
Requesting a job that does not exist through
GET /api/v1/jobs/{job_id}/now returns HTTP 404 with aJob [job_id] not foundmessage instead of HTTP 500. The lookup relied on aNonecheck that the Django ORM never triggers, soJob.DoesNotExistescaped as an unexpected error.
v0.34.0¶
Prelude¶
qiskit_serverless v0.34.0 makes ray an optional client dependency (install with pip install qiskit-serverless[ray] when needed), raises the minimum Qiskit version to 2.2, and removes the previously deprecated widget() interface and qiskit_serverless.visualization module. GPU scheduling is now configured via a gpu flag on the Program model, replacing the provider allowlist. This release also deprecates the distribute_task, get, put, and get_refs_by_status helpers in favour of their Ray equivalents, and includes a range of client bug fixes and UX improvements.
New Features¶
Added a
gpuboolean field to theProgrammodel. When a program is owned by a provider and hasgpuenabled, jobs run from that program are now scheduled with GPU resources. This replaces the previous provider allowlist mechanism, which determined GPU eligibility from a static configuration instead of a per-program flag.
Upgrade Notes¶
cotengrust==0.2.0is now included in the dynamic dependencies allowlist bundled in the Ray runner image. Qiskit Functions that declarecotengrustas a dependency can use it for tensor network contraction path optimization.
The minimum supported Qiskit version for the
qiskit-serverlessclient is now2.2(raised from>=1.4). Since Qiskit 2.1,symengineis no longer a Qiskit dependency, so the client no longer installs it. Reading legacy symengine-encoded QPY payloads (formats 10/11/12 written by Qiskit 1.0–1.1 withuse_symengine=True) is no longer supported; QPY produced by modern Qiskit is unaffected.
Bumped
qiskit-addon-aqc-tensor[quimb-jax]from0.3.0to0.3.1in the dynamic dependencies allowlist bundled in the Ray runner image. Qiskit Functions can now declare and use this newer version.
Custom image names must now be nested under the provider registry prefix. The registry check previously used a plain
startswith, which could accept look-alike hostnames. The check now requires the image to equal the registry or start withregistry/.If you use the local development mock provider (registry
test), rename your image fromtest-local-provider-functiontotest/local-provider-functionand update the correspondingdocker build -ttag in your local workflow.
The
GET /api/v1/programs/{id}/get_jobs/provider listing endpoint now omits theresultfield, bringing it in line with the other cross-author job listing endpoints. Job results are scoped to their author; provider admins listing jobs across authors see job metadata and status only.Provider admins can still read their own job results through the own-scoped job endpoints, which continue to include
result.
raywas removed from the base client requirements and is now provided by therayextra (pip install qiskit-serverless[ray]). If you rely on the Ray runner or on the Ray-only helpers (distribute_task,get,put,get_refs_by_status,remote), install the extra. Using any of those symbols without Ray installed now raises a clearModuleNotFoundErrorinstructing you topip install qiskit-serverless[ray]. The published Ray node image installs the[ray]extra, so its behavior is unchanged.
The deprecated
widget()method has been removed fromBaseClient,ServerlessClient, andIBMServerlessClient. The visualization module (deprecated in 0.33.0) has been completely removed from the package.
Deprecation Notes¶
The
distribute_taskdecorator and theget,putandget_refs_by_statushelper functions have been deprecated and will be removed in following releases. They were thin wrappers around Ray’s native API, which should now be used directly instead:distribute_task-> ray.remoteget-> ray.getput-> ray.putget_refs_by_status-> ray.wait
To migrate,
import rayinside your function and replace the decorator and helpers with their Ray equivalents. You do not need to declarerayas a function dependency: it is already provided by the Qiskit Serverless runtime image that executes your function.Before (using the deprecated Qiskit Serverless wrappers):
from qiskit_serverless import ( get_arguments, save_result, distribute_task, get, ) @distribute_task() def distributed_transpilation(circuit, target_backend): ... # returns an ISA circuit return isa_circuit # launch one task per circuit and collect the results refs = [distributed_transpilation(circuit, backend) for circuit in circuits] isa_circuits = get(refs) save_result({"results": isa_circuits})
After (using Ray directly):
import ray from qiskit_serverless import get_arguments, save_result @ray.remote def distributed_transpilation(circuit, target_backend): ... # returns an ISA circuit return isa_circuit # launch one task per circuit and collect the results refs = [distributed_transpilation.remote(circuit, backend) for circuit in circuits] isa_circuits = ray.get(refs) save_result({"results": isa_circuits})
Uploading the function does not change. Ray is part of the serverless runtime image, so it does not need to be listed in
dependencies:from qiskit_serverless import QiskitFunction function = QiskitFunction( title="function-with-parallel-workflow", entrypoint="function_with_parallel_workflow.py", working_dir="./source_files/", )
To request resources per task (for example GPUs), pass Ray’s native arguments to the decorator, e.g.
@ray.remote(num_cpus=1, num_gpus=1). For more details, see the Ray Core walkthrough.
Bug Fixes¶
Fixed
status()returningRUNNINGfor jobs that report asub_status(e.g.RUNNING: MAPPING). The sub-status is now forwarded correctly when the top-level status isRUNNING.
Authentication failures now surface a clear, actionable message instead of a generic “Credentials couldn’t be verified” error.
If your IBM Cloud account is not entitled to use Qiskit Serverless, the error now explains that your plan is not authorised and instructs you to check your account entitlements, without leaking internal plan identifiers.
If the IBM Runtime API returns an unexpected error during authentication, the response status is forwarded as a friendly message rather than an opaque 500.
The client now passes the server-supplied error message through to the
QiskitServerlessExceptionit raises, so the real reason always reaches the caller.
The ServerlessClient now automatically removes trailing slashes from the gateway host parameter, preventing URL formatting issues when constructing API endpoints. Users can now provide gateway hosts with or without trailing slashes (e.g.,
https://gateway.example.comorhttps://gateway.example.com/).
Non-JSON error responses from the gateway (for example an HTTP 403 block page returned by an ingress proxy) no longer surface as a misleading
QiskitServerlessException: JSON1001: Expecting value: line 1 column 1 (char 0). The client now checks whether the response indicates success before attempting to parse the body as JSON. When the response is not successful and the body is not valid JSON, the HTTP status code and the raw body text are included in the exception message so the real cause is visible to the caller.This affects
upload(),result(),logs(), and most other client API calls.
v0.33.0¶
Prelude¶
qiskit_serverless v0.33.0 is a feature release that expands the IBMServerlessClient with methods to inspect IBM Quantum backends and runtime usage through the Qiskit IBM Runtime service, and adds pre-flight validation to run() so that quota and backend-access problems surface immediately instead of after a silent queue wait. Cloud (instance) authentication now goes through QiskitRuntimeService to align with the Qiskit Runtime APIs. This release also deprecates the Jupyter widget() interface, the unused client name parameter, and the qiskit_serverless.visualization module, updates dependencies, and fixes a couple of bugs from 0.32.0.
New Features¶
IBMServerlessClientnow exposes several methods that wrap the Qiskit IBM RuntimeQiskitRuntimeServiceAPI to interact with IBM Quantum backends:IBMServerlessClient.backends()— Lists IBM Quantum backends accessible through the configured instance. Results are cached per client instance, making repeated calls within a session inexpensive. Userefresh_cache=Trueto force a refresh. WrapsQiskitRuntimeService.backends().IBMServerlessClient.backend()— Fetches a single backend by name and updates the cache. More efficient than listing all backends and validates access. WrapsQiskitRuntimeService.backend().IBMServerlessClient.least_busy()— Returns the backend with the fewest pending jobs that matches the specified criteria. This updates the cache with the retrieved backend. WrapsQiskitRuntimeService.least_busy().IBMServerlessClient.usage()— Returns runtime usage information for the active instance, includingusage_remaining_secondsandusage_limit_reached. WrapsQiskitRuntimeService.usage().
All methods include comprehensive error handling and raise
QiskitServerlessExceptionwith clear error messages when operations fail.
IBMServerlessClient.run()performs three pre-flight checks before submitting a job to the gateway, providing early and clear error messages instead of silent queue waits:Usage quota — raises
QiskitServerlessExceptionwhen the instance has no remaining runtime quota (withinUSAGE_ZERO_EPSILON_SECONDS); emits aUserWarningwhen quota is low (belowUSAGE_LOW_THRESHOLD_SECONDS). Transient failures of the usage endpoint produce a warning rather than blocking the run. The low quota warning can be suppressed by passingsuppress_low_usage_warning=Trueto theIBMServerlessClient.run()method.Backend access — when
arguments["backend_name"]is set, validates access via a single-backend lookup. RaisesQiskitServerlessExceptionif the backend is not found or is inaccessible.Instance has backends — when no
backend_nameis given, verifies the instance exposes at least one backend (result cached). RaisesQiskitServerlessExceptionif none are found.
Upgrade Notes¶
The
qiskit-addon-aqc-tensorpackage bundled in the Ray runner image has been updated from0.2.0to0.3.0(installed with thequimb-jaxextra). Qiskit Functions that rely onqiskit-addon-aqc-tensorshould review the addon’s0.3.0release notes for any API changes.
The minimum supported version of
qiskit-ibm-runtimehas been raised to0.47.0(the supported range is now>=0.47.0,<0.48.0). Users should ensure their environment has a compatibleqiskit-ibm-runtimeinstalled before upgrading.
Several dependencies bundled in the Ray runner image have been updated:
pyscffrom2.11.0to2.13.1qiskit-addon-sqdfrom0.12.0to0.12.1
Qiskit Functions that rely on these packages should review their respective release notes for any API changes.
ServerlessClient.file_download()andServerlessClient.provider_file_download()now always write the downloaded file into the requesteddownload_locationusing only the base name of the target file. Any directory component in thetarget_nameargument (for examplesubdir/result.jsonor a path-traversal sequence such as../result.json) is stripped, so the file is written directly underdownload_location. Code that relied ontarget_namecreating or writing into subdirectories must now pass that subdirectory as part ofdownload_locationinstead. This prevents a crafted file name from escaping the download location.
Two environment variables control the usage quota thresholds used by
IBMServerlessClient.run(). Their defaults are provisional and may be adjusted in a future release:USAGE_LOW_THRESHOLD_SECONDS(default600s) — warn when remaining quota falls below this value.USAGE_ZERO_EPSILON_SECONDS(default1s) — treat remaining quota at or below this as zero and raise an error.
Improved docstrings for
IBMServerlessClientmethods (usage(),backends(),backend(),least_busy(), and_check_usage) to provide clearer descriptions and better examples. All methods now use named parameters when calling the underlying Qiskit IBM RuntimeQiskitRuntimeServicemethods for improved code clarity and maintainability.
Updated
IBMServerlessClientcloud (instance) authentication to useQiskitRuntimeServicefor authentication handling. This aligns authentication behavior with Qiskit Runtime APIs and centralizes credential management.
Deprecation Notes¶
The
nameparameter inBaseClient,ServerlessClient, andIBMServerlessClientis deprecated and will be removed in a future release. The parameter is no longer used for client functionality. Users should remove this parameter from their client instantiation code.Note: The
nameparameter inIBMServerlessClientis NOT deprecated as it is used to load saved accounts.
The
BaseClient.widget()method (and its subclassesServerlessClientandIBMServerlessClient) has been deprecated and will be removed in a future release. The Jupyter widget interface is no longer maintained. UseBaseClient.jobs()andBaseClient.functions()directly to retrieve job and function information, or visit the IBM Quantum web dashboard instead.
The
Widgetclass inqiskit_serverless.visualization.widgetand the entireqiskit_serverless.visualizationmodule have been deprecated and will be removed in a future release. Theipywidgetsandipythondependencies will also be removed at that time.
Bug Fixes¶
Fixed authentication failures for IBM Cloud instances in regions other than the gateway’s default region (for example
eu-de). During authentication the gateway resolves accessible functions via the region-scoped Runtime API, but it previously used a single fixedRUNTIME_API_BASE_URLfor every CRN. A CRN from a non-default region was sent to the default-region host, which returned404 Instance not foundand failed authentication. The gateway now derives the region from the CRN (thecrn:v1:bluemix:public:quantum-computing:<region>:...segment) and routes the functions-access request to the matching regional endpoint. The default region is configurable via theRUNTIME_API_DEFAULT_REGIONenvironment variable (defaultus-east), which is served by the bareRUNTIME_API_BASE_URLhost; other regions use a{region}.host prefix.
Fixed result retrieval for provider (custom-image) functions running on the Ray runner. The function writes its result to a provider-scoped path (
{username}/{provider}/{title}/results/{job_id}.json, via theRESULTS_PATHenvironment variable), but the gateway read the result from a username-only path ({username}/results/{job_id}.json). As a result,job.result()could return an empty result for a provider function even though the job completed successfully.RayResultStorageis now provider-aware, mirroringRayArgumentsStorage, so the read path matches where the function writes.
v0.32.0¶
Prelude¶
qiskit_serverless v0.32.0 is a feature release that improves telemetry collection, updates dependencies and drops Python 3.9 support. Additionally, it fixes a couple of bugs from 0.31.0.
Upgrade Notes¶
Job time limiting is now enforced while a job is in the
PENDINGorRUNNINGstate, rather than being applied once when the job is first queued. This means long-running or stuck jobs will be reliably stopped regardless of how long they spent waiting before execution.Jobs that exceed the time limit are transitioned to the
STOPPEDstate and a warning message is logged.For administrators: the gateway configuration key
programTimeoutDayshas been renamed toprogramTimeoutHours. The default timeout is 24 hours and can be overridden with thePROGRAM_TIMEOUTenvironment variable.
Python 3.9 has reached end-of-life and is no longer supported. The minimum supported Python version is now
3.10. Users still on Python 3.9 should upgrade before installing this release.
Qiskit Serverless is now compatible with
qiskit-ibm-runtime<0.48.0. Users can upgrade their local installation before using this release:pip install "qiskit-ibm-runtime==0.47.0"
Bug Fixes¶
The
Job.error_message()method now correctly returns error details for jobs that use the events-based error reporting introduced in a previous release, while remaining backward compatible with jobs whose errors were stored in the legacy format.
Other Notes¶
Internal improvements to telemetry collection and observability infrastructure, including better integration of OpenTelemetry instrumentation across the API layer.
0.31.0¶
Prelude¶
qiskit_serverless v0.31.0 introduces error event tracking for Qiskit Functions, structured JSON logging across all components, and a range of scheduler observability and reliability improvements.
New Features¶
Added comprehensive error tracking and event management capabilities for Qiskit Functions. This feature enables function developers to send custom error events via
send_error()or raise structured exceptions viaServerlessError, and allows users to retrieve and inspect these events for debugging and monitoring purposes.Function development
Function developers can now use two new capabilities:
A new
send_error()function to register custom error events that will be stored in the gateway and associated with the job. This is particularly useful for tracking application-specific errors, validation failures, or custom error conditions. Each event is represented by aJobEventobject.It can be used like this:
from qiskit_serverless import send_error # Send a simple error send_error( code="ERR001", message="Invalid input parameter", exception="ValueError" ) # Send an error with additional context send_error( code="ERR002", message="Circuit optimization failed", exception="OptimizationError", args={ "circuit_depth": 150, "num_qubits": 127, "optimization_level": 3 } )
A new
ServerlessErrorexception class to raise structured, trackable errors. When aServerlessErroris raised in a function, it is automatically caught by the framework, logged as an ERROR event, and can be retrieved by users through the events API.The
ServerlessErrorclass provides a structured way to communicate errors with:code: A unique error code for categorizationmessage: Human-readable error descriptiondetails: Additional context (can be any JSON-serializable data)
Example usage:
from qiskit_serverless import ServerlessError # Raise a structured error raise ServerlessError( code="VAL001", message="Invalid circuit depth", details={"max_depth": 100, "provided_depth": 150} )
Designing custom error classes
Function developers can subclass
ServerlessErrorto build domain-specific exception hierarchies. The framework records the name as theexceptionfield in the event, so subclass names appear directly in the events retrieved by users, making errors easier to categorize and filter.The simplest form requires no
__init__override:from qiskit_serverless import ServerlessError class ProviderError(ServerlessError): """Base error for all errors raised by this provider.""" class ValidationError(ProviderError): """Raised when input arguments fail validation.""" class ResourceError(ProviderError): """Raised when a required resource is unavailable."""
Raise them exactly as you would
ServerlessError:raise ValidationError( code="VAL001", message="num_qubits exceeds the maximum allowed value", details={"max": 127, "provided": 256} )
On the client side, the
exceptionfield of the retrieved event will be"ValidationError"rather than"ServerlessError", which lets users filter precisely:error_events = job.events(type="ERROR") for event in error_events: if event.data.get("exception") == "ValidationError": print("Input problem:", event.data["message"])
You can also override
__init__to fix acodeprefix or add mandatory fields, so callers only need to provide the varying parts:class CircuitError(ProviderError): """Raised for circuit-related failures.""" def __init__(self, message: str, circuit_id: str): super().__init__( code="CIR001", message=message, details={"circuit_id": circuit_id}, ) raise CircuitError("Circuit depth exceeds limit", circuit_id="circ-42")
When to use ServerlessError vs send_error
Use
ServerlessErrorwhen you want to stop execution and signal a fatal error that prevents the function from completing successfully. The error will be automatically logged, the job will transition to ERROR status, and the structured error message will be raised as aQiskitServerlessExceptionwhen the user callsjob.result():QiskitServerlessException: | Message: num_qubits exceeds the maximum allowed value | Code: VAL001 | Exception: ValidationError | Details: | - max: 127 | - provided: 256
Use
send_error()when you want to log an error but continue execution. This is useful for non-fatal errors, warnings, or when you want to track multiple issues without stopping the function. Events sent this way are still surfaced injob.result()if the job ultimately ends in ERROR status.
Example combining both approaches:
from qiskit_serverless import ServerlessError, send_error def process_circuits(circuits): failed = 0 for circuit in circuits: if circuit.num_qubits > 127: # Log non-fatal error, continue processing send_error( code="SKIP001", message="Circuit exceeds qubit limit", exception="ValidationError", args={"num_qubits": circuit.num_qubits} ) failed += 1 continue process(circuit) # Raise fatal error if all circuits failed if failed == len(circuits): raise ServerlessError( code="FATAL001", message="All circuits failed", details={"total": len(circuits)} )
Client side
Users can retrieve job events using the new
events()method available on both class:.Job objects and class:.ServerlessClient instances. Events can be filtered by type or retrieved in bulk for comprehensive debugging. Each event is represented by aJobEventobject with the following attributes:event_type: Type of event (e.g., “ERROR”, “STATUS_CHANGE”)origin: Where the event originated (e.g., “API”, “SCHEDULER”, “FUNCTION”)context: Context in which event was raised (e.g., “SEND_ERROR”, “SET_SUB_STATUS”)created: ISO 8601 timestamp of event creationdata: Dictionary containing event-specific data (for ERROR events: code, message, exception, args)
Retrieve all events for a job:
from qiskit_serverless import ServerlessClient serverless = ServerlessClient(...) job = serverless.run("my-function", arguments={"param": "value"}) # Get all events all_events = job.events() for event in all_events: print(f"Type: {event.event_type}") print(f"Created: {event.created}") print(f"Data: {event.data}")
To retrieve error events, users can filter events by type:
# Get only error events error_events = job.events(type="ERROR") for error in error_events: print(f"Error Code: {error.data.get('code')}") print(f"Message: {error.data.get('message')}") print(f"Exception: {error.data.get('exception')}") if 'args' in error.data: print(f"Additional Info: {error.data['args']}")
On top of the
Jobmethods, users can retrieve events using the client directly:# Alternative: use client to get events by job_id events = serverless.events(job_id="my-job-id", type="ERROR")
API
Two new REST API endpoints have been added:
GET /api/v1/jobs/{job_id}/events/: Retrieve job eventsPOST /api/v1/jobs/{job_id}/event/: Create a new job event
Upgrade Notes¶
The gateway, scheduler, and core components now emit structured JSON logs by default. Operators using log aggregation tools (e.g. Elasticsearch, Splunk) will see log lines formatted as JSON objects rather than plain text. The log level can still be configured via the existing
LOG_LEVELenvironment variable.
The scheduler now tracks metrics broken down per provider, enabling more granular observability of job throughput and resource usage when multiple providers are configured. No configuration change is required; existing dashboards will see new label dimensions on scheduler metrics.
Qiskit Serverless is now compatible with
qiskit-ibm-runtime==0.47. Users can upgrade their local installation before using this release:pip install "qiskit-ibm-runtime==0.47"
v0.30.1¶
Prelude¶
qiskit_serverless v0.30.1 is a small patch release that fixes a minor client issue, introduces a series of API/Gateway/Scheduler improvements that increase the health of the deployed service, and updates the base image with the newest dependency versions.
Bug Fixes¶
Fixed gateway triggering out of memory errors when downloading a big file. Now, the download uses a 64Kb stream buffer that prevents it from crashing.
Fixed a bug in
ServerlessClient.upload()where invalid files would not raise an error and instead fail to upload silently. The method now correctly raises aQiskitServerlessException.
v0.30.0¶
Prelude¶
The main feature in this release is the major refactor in logs to differentiate between provider logs and user logs and optimize storage. The logs are now stored in COS while keeping backward compatibility.
New Features¶
The
qiskit-serverlessPython library added two new utilities,get_logger()andget_provider_logger(), available to Qiskit Function developers. Developers should use these functions within their source code to distinguish which logging information is relevant for users (get_logger()) or providers (get_provider_logger()) respectively. These functions create[PUBLIC]and[PRIVATE]prefixes under the hood to allow the service to filter the information appropriately. To keep intellectual property safe, only function users can access user logs, and only providers can access provider logs. For example:from qiskit_serverless import get_logger, get_provider_logger user_logger = get_logger() provider_logger = get_provider_logger() get_logger().info("User log") user_logger.info("User multiline\nlog") user_logger.warning("User log") user_logger.error("User log") get_provider_logger().info("Provider log") provider_logger.info("Provider multiline\nlog") provider_logger.warning("Provider log") provider_logger.error("Provider log")
The
ServerlessClientandJobclasses’logs()method will from now on only return user logs. To access provider logs, we have added a newprovider_logs()method. For example:runnable_function = serverless_client.function("my_function") job = runnable_function.run() print(job.logs()) # only users print(job.provider_logs()) # only providers
Uploaded files now should have a valid file type in order to be accepted by the platform.
The accepted MIME types for uploaded files are:
application/x-tar (.tar)
application/gzip (.gz, .tgz)
application/json (.json)
application/octet-stream (generic binary; may include .bin, .dat, .exe)
application/zip (.zip)
text/plain (.txt, .log)
text/csv (.csv)
Upgrade Notes¶
Added a new
versionfield to theProgramDjango model. This field is used to track the version of the program (function).
Added a new
JobEventstable to our database to improve metrics and provide a more flexible foundation for future event-tracking features. Each time a job changes state, a new event is now recorded in the database.- The new
JobEventstable includes: id: auto-generated UUIDjob: foreign key referencing the jobs tablecreated: timestamp automatically set at event creationevent_type: string describing the event type (currently"Status change")context: string indicating where the change originated (e.g., Scheduler, API)data: JSON payload containing event‑specific details
- The new
Added several quality of life improvements in testing.
The Scheduler is modified to upload logs to COS when a job transitions from running to a terminal state. At that moment, the logs will be filtered based on the prefixes, and the information will be saved in the corresponding folder inside COS.
The Gateway endpoint
/logshas been modified to only target user logs, and a new /provider_logs` has been added for provider logs. Both should return: 1. The COS log for finished jobs, if it exists. This was previously filtered in the Scheduler. 2. The Ray console logs if the job is running. This is filtered live. 3. As a fallback, logs from the database.
Four new exception classes have been added to the gateway API to better differentiate between different failure scenarios:
JobNotFoundException,ProviderNotFoundException,FunctionNotFoundExceptionandFileNotFoundExceptionthat inherit from an abstractNotFoundErrorbase class.
Added a new gateway setting to limit the number of active jobs per user. By setting the environment variable
LIMITS_ACTIVE_JOBS_PER_USER, you can restrict the total number of jobs a user can have acrossQUEUED,PENDING, andRUNNINGstates. The default limit is50.
Requests to run programs will now return an
HTTP 429 Too Many Requestsresponse if a user attempts to start a new job while they are at their active job limit.
The Scheduler and API code have been refactored to improve their maintainability and scalability. Most changes are internal and do not affect the user experience, but some additions have been made, for example, the scheduler can now respond to
SIGINTandSIGTERMsignals, and the API now accepts a dynamic configuration system that allows changing application settings at runtime.
Deprecation Notes¶
The
@distribute_qiskit_functiondecorator has been deprecated and will be removed in following releases. The decorator was designed for remote program execution, a functionality that is now provided through the different serverless clients through theuploadmethod.
Bug Fixes¶
Fixed a bug in the function versioning workflow where the version set upon function creation couldn’t be uploaded to the platform, stored in the database, or retrieved upon function retrieval. After the fix, the function version can be tracked through the whole life cycle. For example:
from qiskit_serverless import QiskitFunction my-func = QiskitFunction( title="my_func_title", entrypoint="my_func_entrypoint.py", working_dir="./source_files/", version="2.0.0", ) # this print outputs 2.0.0 print(my-func.version) serverless.upload(my-func) my-func-load = serverless.function("my_func_title") # this print now also outputs 2.0.0 (previously empty) print(my-func-load.version)
Fixed an issue that affected local testing when using custom functions packaged as Docker images. These custom functions are registered as “provider” functions, however, their data path was resolved to a “custom” function data path, resulting in a “File not found” error when trying to fetch function arguments. After the fix, the data paths are resolved correctly, and no error is raised:
For user functions:
DATA_PATH = \data\usernameFor provider functions:
DATA_PATH = \data\username\providername\imagename
v0.29.0¶
Upgrade Notes¶
Refactored storage service initialization to accept
Programmodel instances instead of individual parameters. TheFileStorageandArgumentsStorageclasses now accept afunctionparameter (Program model instance) rather than separateusername,function_title, andprovider_nameparameters. This change improves code cohesion by reducing the number of parameters passed between components and ensures consistent access to program metadata across storage services.
Removed unused
function_titleandprovider_nameparameters fromProgramViewSet.run()method’s call tojob_serializer.save()as these parameters are no longer used after the storage service refactoring.
Removed
LocalClientandRayClientclasses and their usages in the tests. For testing, one should useServerlessClientwith default values as indocs/deployment/example_custom_image_function.rst. In addition, updated tests and removed irrelevant comments.
The legacy IBM Quantum authentication channel (
ibm_quantum) has been removed. Users should migrate to using the IBM Quantum Platform channel (ibm_quantum_platform) for authentication. The authentication logic has been simplified to support onlyibm_cloudandibm_quantum_platformchannels. When no channel header is provided and a CRN is present, the system defaults toibm_quantum_platform.
Qiskit Serverless now supports the latest version of the
qiskit-ibm-runtimepackage:qiskit-ibm-runtime==0.45.
Bug Fixes¶
Fixed a bug in the json decoder that would crop the response details to the first character when gateway errors were raised. This utility now forwards the full error message to the raised
QiskitServerlessException.
Fixed error handling when a function is not found. Instead of providing a bare 404 error, the
QiskitServerlessExceptionnow contains a more meaningful error message:QiskitServerlessException: | Message: Http bad request. | Code: 404 | Details: User program 'my-program' was not found or you do not have permission to view it.
Fixes https://github.com/Qiskit/qiskit-serverless/issues/1773.
Fixed a bug in
FunctionRepository.get_user_function()where functions with providers could be incorrectly returned when searching for user functions without providers. The method now correctly filters byprovider=Noneto ensure only user-owned functions without providers are returned. This prevents incorrect storage path resolution when users have multiple functions with the same title.
v0.28.0¶
New Features¶
IBMServerlessClientnow supports custom gateway host URLs through thehostparameter. This allows for a more streamlined testing of the client connecting to non-production gateways.
Added a new
ProgramHistorymodel and database table to track when entities perform actions to add or remove an instance from a program. These allow to audit access changes for bothinstancesandtrial_instances.
v0.27.1¶
Upgrade Notes¶
The scheduling logic that was managing non GPU and GPU jobs was improved. Now the scheduler manages both type of jobs independently so you can adjust separately where each of these jobs are run.
Qiskit Serverless now supports the latest version of the
qiskit-ibm-runtimepackage:qiskit-ibm-runtime==0.43.
Bug Fixes¶
Fixed a bug in the scheduler that was preventing it from stopping jobs automatically after the timeout threshold specified with the environment variable
PROGRAM_TIMEOUT.
v0.27.0¶
New Features¶
A new utility
get_runtime_service()is now available to simplify the instantiation of aQiskitRuntimeServicewithin a function. It automatically pulls credentials from environment variables, reducing boilerplate code and improving usability for function developers.Example usage:
from qiskit_serverless import get_runtime_service service = get_runtime_service() backend = service.backend("ibm_fez")
This is equivalent to:
import os from qiskit_serverless import get_arguments, save_result from qiskit_ibm_runtime import QiskitRuntimeService service = QiskitRuntimeService( channel=os.environ["QISKIT_IBM_CHANNEL"], instance=os.environ["QISKIT_IBM_INSTANCE"], token=os.environ["QISKIT_IBM_TOKEN"], ) backend = service.backend("ibm_fez")
This function also enables automatic tracking of runtime job and session IDs created during function execution. It’s important to note that tracking will only be possible if the function runtime jobs are submitted through a service instantiated with this function.
On top of the default credentials, function developers can customize the call to
get_runtime_service()with custom input parameters, includingtoken,instance,channelandurl. For example:from qiskit_serverless import get_runtime_service service = get_runtime_service(channel="ibm_quantum_platform", token="staging_token", instance="staging_crn", url="staging_url") backend = service.backend("staging_backend")
When using
get_runtime_service()inside a serverless function, the resulting job object now supports two new methods:job.runtime_jobs()andjob.runtime_sessions(). These methods return lists of job/session IDs that can be used to fetch job objects from aQiskitRuntimeServiceor access IQP dashboards.job.runtime_jobs()accepts an optionalruntime_sessionparameter that allows to filter the returned jobs by associated session id. For example:job = function.run(...) runtime_ids = job.runtime_jobs() # out = ["job_id_1", "job_id_2", "job_id_3"...] runtime_sessions = job.runtime_sessions() # out = ["session_id_1", "session_id_2"] # a specific session id can be passed to the runtime_jobs() method to filter by session: session_id = job.runtime_sessions()[0] # out = "session_id_1" session_job_ids = job.runtime_jobs(session_id) # in this example, only job ids 1 and 3 correspond to session_id_1: # out = ["job_id_1", "job_id_3"]
Upgrade Notes¶
Added a new AccessPolicy for User model to be able to allow or not the access to the service by the
is_activeparameter.
Enhanced
job.cancel()behavior to use the newly introduced features.job.cancel()now attempts to instantiate aQiskitRuntimeServiceusing the credentials from theServerlessClient, allowing automatic canceling of associated runtime jobs. This works when the credentials used in the function match those in the client, which happens by default when usingget_runtime_service()with no additional inputs.To support local testing or non-standard runtime URLs (e.g., staging environments), where the
ServerlessClientdon’t match those in theQiskitRuntimeServiceused to submit the jobs,job.cancel()accepts a service parameter:service = QiskitRuntimeService( channel="ibm_quantum_platform", token="MY_TOKEN", instance="MY_CRN", url="my.staging.url.com" ) job.cancel(service)
The
ServerlessRuntimeServiceclass has been updated to support changes introduced inqiskit_ibm_runtime>=0.42, unlocking compatibility of the qiskit-serverless>=0.27.0 package withqiskit_ibm_runtime>=0.42. For older versions ofqiskit-serverless,qiskit_ibm_runtime<0.42will still be required.
The Scheduler will start to manage the size of the logs generated by the Qiskit Functions. The environment variable
FUNCTIONS_LOGS_SIZE_LIMITwill be in charge of the maximum size that the system will allow to store.
Enhanced
client.jobs()andfunction.jobs()behavior with new filters to improve the management of the different jobs. Now you can filter bystatusand bycreated_afterto retrieve those specific jobs. For example:# Filtering by status it will retrieve all the jobs with that status client.jobs(status="SUCCEEDED") # The same it will apply after a specific date time_filter = datetime.now(timezone.utc) client.jobs(created_after=time_filter) # And all these new filters can be combined with the Qiskit Function filter # to be able to return running jobs from the specific Qiskit Function function.jobs(status="RUNNING")