When you need this
A launch, resize, volume attach, node pool update or load balancer change "succeeded" in the CLI or console, but the resource never changed. Or a script hangs waiting on an OCID whose state never moves. The API call only accepted the request. The actual work runs asynchronously and is tracked as a work request. A work request also carries the error message you never saw.
Use this sheet to:
- find the work request behind a resource
- read its status, percent complete and errors
- wait on it properly in scripts
Tip
Work request errors often hold the real cause: an out-of-capacity condition, a quota, a missing policy or a conflicting operation. Read them before you retry. Blind retries can queue up conflicting requests.
Which command group to use
Work requests are not one global list. Each service exposes its own, and the CLI groups differ.
| Service | List command | Notes |
|---|---|---|
| Compute and other Core operations | oci work-requests work-request list | Generic Work Requests API |
| OKE clusters and node pools | oci ce work-request list | Filters for cluster, resource type and status |
| Load Balancer | oci lb work-request list | Scoped to one load balancer |
| Connector Hub | oci sch work-request list | |
| MySQL HeatWave | oci mysql work-request list | |
| Other services | oci <service> work-request --help | Many services have their own group. Names vary by service and CLI version |
If you're not sure, run oci <service> --help and look for work-request. Resource Manager is different: it uses jobs (oci resource-manager job), not work requests.
Generic work requests (Compute and Core)
List recent work requests in a compartment
C=ocid1.compartment.oc1..aaaa...
oci work-requests work-request list -c "$C" --all \
--query 'data[].{op:"operation-type",status:status,pct:"percent-complete",accepted:"time-accepted",id:id}' \
--output table
The generic list has no --status or --sort-by filter. Filter in JMESPath instead:
# Only failed work requests
oci work-requests work-request list -c "$C" --all \
--query 'data[?status==`FAILED`].{op:"operation-type",accepted:"time-accepted",id:id}' \
--output table
Status values are typically ACCEPTED, IN_PROGRESS, SUCCEEDED, FAILED, CANCELING and CANCELED. Check your own output for the exact strings.
Find the work request for one resource
INSTANCE=ocid1.instance.oc1..aaaa...
oci work-requests work-request list -c "$C" --resource-id "$INSTANCE" --all \
--query 'data[].{op:"operation-type",status:status,id:id}' --output table
Get details, errors and log entries
WR=ocid1.coreservicesworkrequest.oc1..aaaa... # OCID prefix varies by service
# Status, percent complete and the resources it touched
oci work-requests work-request get --work-request-id "$WR"
# The error messages - start here when status is FAILED
oci work-requests work-request-error list --work-request-id "$WR" --all \
--query 'data[].{code:code,message:message,time:timestamp}' --output table
# Step-by-step log of what the service did
oci work-requests work-request-log-entry list --work-request-id "$WR" --all \
--sort-order ASC --query 'data[].{time:timestamp,msg:message}' --output table
The generic group has no cancel command. To stop an operation, use the resource's own API where one exists, or let it finish and reverse the change.
OKE work requests
OKE has richer filters, so use them:
CLUSTER=ocid1.cluster.oc1..aaaa...
# Failed node pool operations on one cluster
oci ce work-request list -c "$C" --cluster-id "$CLUSTER" \
--resource-type NODEPOOL --status FAILED \
--sort-by TIME_ACCEPTED --sort-order DESC --output table
# Errors and logs for one of them
oci ce work-request-error list --work-request-id "$WR"
oci ce work-request-log-entry list --work-request-id "$WR"
--resource-type takes CLUSTER or NODEPOOL. You can pass --status more than once, for example --status IN_PROGRESS --status ACCEPTED, to see what is still running.
Warning
Starting a second node pool update or upgrade while one is
IN_PROGRESSusually fails or queues behind it. Check for in-flight work requests before you retry a cluster or node pool change.
Load Balancer work requests
Every listener, backend set, certificate or backend change on a load balancer is a work request. Changes to one load balancer apply one after another, so a stuck or failed one explains why later changes "don't apply".
LB=ocid1.loadbalancer.oc1..aaaa...
oci lb work-request list --load-balancer-id "$LB" --all \
--query 'data[].{type:type,state:"lifecycle-state",msg:message,accepted:"time-accepted",id:id}' \
--output table
oci lb work-request get --work-request-id "$WR" --query 'data."error-details"'
Field names here differ from the generic API (lifecycle-state instead of status). Run one command without --query first to see the shape in your CLI version.
Common errors and what they mean
| Error text (paraphrased) | Cause | Fix |
|---|---|---|
| Out of host capacity | No capacity for that shape in the AD or fault domain | Try another AD or fault domain or a flex shape size, or use a capacity reservation |
| LimitExceeded / QuotaExceeded | Service limit or compartment quota reached | Raise the limit or quota, or free capacity |
| Conflict / resource busy | Another operation is running on the same resource | Wait for the in-flight work request, then retry |
| NotAuthorizedOrNotFound inside the error | The service lacks a policy on a dependent resource (subnet, key, image) | Add the missing policy and check the dependent OCID and its compartment |
| Image or shape not compatible | Image doesn't support the shape (for example, x86 image on Arm) | Pick a compatible image and shape pair |
Waiting on work in scripts
Don't poll the resource state in a tight loop. Use the CLI's built-in waiters. Most create and update commands accept --wait-for-state and wait on the work request or the resource:
oci compute instance action --instance-id "$INSTANCE" --action SOFTRESET \
--wait-for-state RUNNING --max-wait-seconds 900 --wait-interval-seconds 15
Some commands wait on the work request itself and accept states like SUCCEEDED and FAILED. Check the command's --help to see which states it accepts. If a waiter times out, the CLI exits non-zero. The work request may still be running, so look it up before you retry.
A simple polling fallback for any generic work request:
while :; do
S=$(oci work-requests work-request get --work-request-id "$WR" --query 'data.status' --raw-output)
echo "$(date -u +%T) $S"
case "$S" in SUCCEEDED) break ;; FAILED|CANCELED)
oci work-requests work-request-error list --work-request-id "$WR" --all; exit 1 ;; esac
sleep 20
done
PowerShell equivalent
$C = "ocid1.compartment.oc1..aaaa..."
oci work-requests work-request list -c $C --all | ConvertFrom-Json |
Select-Object -ExpandProperty data |
Where-Object { $_.status -eq 'FAILED' } |
Select-Object 'operation-type', 'time-accepted', id
Prevent it next time
- In automation, always capture the
opc-work-request-id(shown in--debugoutput and returned by many commands). Log it next to the resource OCID so you can trace the failure later. - Make scripts fail loudly. After a waiter or poll loop ends in
FAILED, printwork-request-error listbefore exiting. - Check for in-flight work requests before a change on OKE node pools and load balancers, so you don't stack conflicting operations.
- Use OCI Audit to see who started an operation. Use work requests to see what happened to it.