Loup
11/25/2025, 10:47 AMMarvin
11/25/2025, 10:48 AMMarvin
11/25/2025, 10:51 AM.deploy(...), or CLI prefect deploy --job-variable ....
Step 1 — add resources to your Kubernetes work pool template
- Prefect UI > Work Pools > your K8s pool > Edit > Advanced > Base job template
- Add a resources section to the main container and expose variables:
{
"apiVersion": "batch/v1",
"kind": "Job",
"metadata": {
"labels": "{{ labels }}",
"namespace": "{{ namespace }}",
"generateName": "{{ name }}-"
},
"spec": {
"backoffLimit": "{{ backoff_limit }}",
"ttlSecondsAfterFinished": "{{ finished_job_ttl }}",
"template": {
"spec": {
"restartPolicy": "Never",
"serviceAccountName": "{{ service_account_name }}",
"containers": [
{
"name": "prefect-job",
"image": "{{ image }}",
"imagePullPolicy": "{{ image_pull_policy }}",
"env": "{{ env }}",
"args": "{{ command }}",
"resources": {
"requests": {
"memory": "{{ memory_request }}",
"cpu": "{{ cpu_request }}"
},
"limits": {
"memory": "{{ memory_limit }}",
"cpu": "{{ cpu_limit }}"
}
}
}
]
}
}
},
"variables": {
"type": "object",
"properties": {
"memory_request": {
"type": "string",
"default": "256Mi"
},
"cpu_request": {
"type": "string",
"default": "100m"
},
"memory_limit": {
"type": "string",
"default": "512Mi"
},
"cpu_limit": {
"type": "string",
"default": "500m"
}
}
}
}
Step 2 — override per deployment (pick one)
- prefect.yaml
deployments:
- name: my-deployment
entrypoint: flows/my_flow.py:my_flow
work_pool:
name: my-k8s-pool
job_variables:
memory_request: "1Gi"
cpu_request: "500m"
memory_limit: "2Gi"
cpu_limit: "1"
- Python
from prefect import flow
@flow
def my_flow():
...
my_flow.deploy(
name="my-deployment",
work_pool_name="my-k8s-pool",
job_variables={
"memory_request": "1Gi",
"cpu_request": "500m",
"memory_limit": "2Gi",
"cpu_limit": "1",
},
)
- CLI
prefect deploy \
--name my-deployment \
--pool my-k8s-pool \
--job-variable memory_request=1Gi \
--job-variable cpu_request=500m \
--job-variable memory_limit=2Gi \
--job-variable cpu_limit=1
Notes
- Use standard K8s quantities: memory like 256Mi/1Gi; CPU like 250m/1/2.
- Requests determine scheduling and influence cluster autoscaler behavior; limits enforce max usage. For “autoscaling while the deployment is running,” requests are the key inputs for cluster autoscaler to provision nodes that fit your pod.
- If every flow run should use the same resources, you can hard-code them in the template instead of templating variables.
References
- Kubernetes worker docs (base job template and variables): prefect-kubernetes docs
- Flow.deploy API (supports job_variables): Prefect docs
If you share your current base job template, I can help patch it with the exact resources block you need.Loup
11/26/2025, 5:25 PMapiVersion: <http://argoproj.io/v1alpha1|argoproj.io/v1alpha1>
kind: Application
metadata:
name: prefect
namespace: argocd
spec:
project: default
sources:
- repoURL: <https://prefecthq.github.io/prefect-helm>
chart: prefect-server
targetRevision: 2025.11.21180339
helm:
valuesObject:
server:
replicaCount: 1
basicAuth:
enabled: true
existingSecret: "prefect-auth-secret"
uiConfig:
prefectUiApiUrl: "<https://prefect.recomend.app/api>"
env:
- name: PREFECT_SERVER_API_CSRF_PROTECTION_ENABLED
value: "true"
postgresql:
enabled: true
primary:
persistence:
enabled: true
storageClass: hcloud-volumes
size: 10Gi
annotations:
<http://resize.topolvm.io/storage_limit|resize.topolvm.io/storage_limit>: "50Gi"
<http://resize.topolvm.io/threshold|resize.topolvm.io/threshold>: "20%"
<http://resize.topolvm.io/increase|resize.topolvm.io/increase>: "25%"
<http://backup.velero.io/backup-volumes|backup.velero.io/backup-volumes>: "data"
- repoURL: <https://prefecthq.github.io/prefect-helm>
chart: prefect-worker
targetRevision: 2025.11.21180339
helm:
valuesObject:
worker:
apiConfig: selfHostedServer
config:
workPool: kube
selfHostedServerApiConfig:
apiUrl: "<http://prefect-server.prefect.svc.cluster.local:4200/api>"
basicAuth:
enabled: true
existingSecret: "prefect-auth-secret"
- repoURL: <https://github.com/recomendapp/infra.git>
targetRevision: main
path: apps/services/prefect
directory:
recurse: true
destination:
server: <https://kubernetes.default.svc>
namespace: prefect
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- ServerSideApply=true
I have other file in apps/services/prefect so how Im suppoed to setup cpu memory, etc... ?Marvin
11/26/2025, 5:25 PMMarvin
11/26/2025, 5:29 PMworker.resources (and optional worker.autoscaling).
- This controls the controller pod that submits Jobs, not your flow run pods.
2) Flow run Job resources (the pods that actually execute your flow)
- Configure in the Kubernetes work pool’s base job template (and optionally override per deployment via job_variables).
- This is what Kubernetes uses for scheduling and cluster autoscaling decisions for each flow run.
Below are working snippets tailored to your Argo CD Application (multi-source) setup.
A) Set worker pod CPU/memory (prefect-worker chart)
Add these to the prefect-worker source’s helm.valuesObject (where you already set worker.apiConfig and config.workPool):
worker:
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1"
memory: "2Gi"
# Optional: HPA for the worker controller pod
autoscaling:
enabled: true
minReplicas: 1
maxReplicas: 3
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 80
B) Set flow run Job CPU/memory (base job template on the work pool)
You have two options. Pick one.
Option 1 — Inline in Helm values (simple)
Add a JSON base job template that sets resources on the main container and exposes variables you can override per deployment:
worker:
config:
workPool: kube
baseJobTemplate:
configuration: |
{
"variables": {
"cpu_request": { "type": "string", "default": "500m" },
"memory_request": { "type": "string", "default": "1Gi" },
"cpu_limit": { "type": "string", "default": "1" },
"memory_limit": { "type": "string", "default": "2Gi" }
},
"job_configuration": {
"job_manifest": {
"spec": {
"template": {
"spec": {
"restartPolicy": "Never",
"containers": [
{
"name": "prefect-job",
"resources": {
"requests": {
"cpu": "{{ cpu_request }}",
"memory": "{{ memory_request }}"
},
"limits": {
"cpu": "{{ cpu_limit }}",
"memory": "{{ memory_limit }}"
}
}
}
]
}
}
}
}
}
}
Option 2 — Store JSON in your repo and reference it (nice for GitOps)
Since you have apps/services/prefect in your Argo CD app, add a ConfigMap there with the template:
apps/services/prefect/base-job-template-cm.yaml
```
apiVersion: v1
kind: ConfigMap
metadata:
name: prefect-base-job-template
namespace: prefect
data:
baseJobTemplate.json: |
{
"variables": {
"cpu_request": { "type": "string", "default": "500m" },
"memory_request": { "type": "string", "default": "1Gi" },
"cpu_limit": { "type": "string", "default": "1" },
"memory_limit": { "type": "string", "default": "2Gi" }
},
"job_configuration": {
"job_manifest": {
"spec": {
"template": {
"spec": {
"restartPolicy": "Never",
"containers": [
{
"name": "prefect-job",
"resources": {
"requests": {
"cpu": "{{ cpu_request }}",
"memory": "{{ memory_request }}"
},
"limits": {
"cpu": "{{ cpu_limit }}",Marvin
11/26/2025, 5:29 PMThen point the Helm chart at that ConfigMap in the `prefect-worker` source values:
worker:
config:
workPool: kube
baseJobTemplate:
existingConfigMapName: prefect-base-job-template
C) Override per deployment (optional, when one flow needs more/less)
- In prefect.yaml:
deployments:
- name: heavy
entrypoint: flows/heavy.py:run
work_pool:
name: kube
job_variables:
cpu_request: "1500m"
memory_request: "3Gi"
cpu_limit: "2"
memory_limit: "5Gi"
- Or via CLI:
prefect deploy \
--name heavy \
--pool kube \
--job-variable cpu_request=1500m \
--job-variable memory_request=3Gi \
--job-variable cpu_limit=2 \
--job-variable memory_limit=5Gi
```
Notes
- Use standard K8s quantities: memory like 256Mi/1Gi; CPU like 250m/1/2.
- Jobs don’t “autoscale” replicas by default; instead, set realistic requests so the cluster autoscaler can provision nodes to fit your pods. If you need horizontal scaling of work, run more concurrent flow runs (or use Dask/Ray/etc. in your flow).
- The Helm chart will sync the base job template to the specified work pool on startup; changing these values and letting Argo CD roll the worker is enough to update the pool template.
Helpful docs
- Prefect Helm charts: prefect-helm
- Kubernetes worker docs (base job template + variables): prefect-kubernetes integration
- Prefect 3 deployments and job variables: Prefect docs
Quick check: Do you want these resources set for the worker pod, the flow run Job pods, or both? I can tailor the exact Argo CD Application snippet accordingly.Loup
11/26/2025, 5:38 PMapps/services/prefect/ directory :
apiVersion: v1
kind: ConfigMap
metadata:
name: prefect-base-job-template
namespace: prefect
data:
baseJobTemplate.json: |
{
"variables": {
"cpu_request": { "type": "string", "default": "500m" },
"memory_request": { "type": "string", "default": "1Gi" },
"cpu_limit": { "type": "string", "default": "1" },
"memory_limit": { "type": "string", "default": "2Gi" }
},
"job_configuration": {
"job_manifest": {
"spec": {
"template": {
"spec": {
"restartPolicy": "Never",
"containers": [
{
"name": "prefect-job",
"resources": {
"requests": {
"cpu": "{{ cpu_request }}",
"memory": "{{ memory_request }}"
},
"limits": {
"cpu": "{{ cpu_limit }}",
"memory": "{{ memory_limit }}"
}
}
}
]
}
}
}
}
}
}
I have others file in apps/services/prefect :
─ tree apps/services/prefect ─╯
apps/services/prefect
├── base-job-template-cm.yaml
├── ingress.yaml
├── job-init.yaml
├── kustomization.yaml
└── secrets.yaml
So should I add the new base-job-template-cm.yaml to kustomization.yaml ?
kustomization.yaml :
resources:
- ingress.yaml
- secrets.yaml
- job-init.yamlMarvin
11/26/2025, 5:38 PMMarvin
11/26/2025, 5:39 PMresources:
- ingress.yaml
- secrets.yaml
- job-init.yaml
- base-job-template-cm.yaml
2) Tell the worker chart to use that ConfigMap
In your Argo CD Application, under the prefect-worker source, extend valuesObject to reference the ConfigMap:
- repoURL: <https://prefecthq.github.io/prefect-helm>
chart: prefect-worker
targetRevision: 2025.11.21180339
helm:
valuesObject:
worker:
apiConfig: selfHostedServer
config:
workPool: kube
baseJobTemplate:
existingConfigMapName: prefect-base-job-template
selfHostedServerApiConfig:
apiUrl: "<http://prefect-server.prefect.svc.cluster.local:4200/api>"
basicAuth:
enabled: true
existingSecret: "prefect-auth-secret"
After committing, let Argo CD sync. The worker’s init step will sync this base job template into the kube work pool. From then on, each flow run Job will have the CPU/memory requests/limits you templated, and you can still override them per-deployment via job_variables.
Sanity checks
- Ensure the CM key is exactly baseJobTemplate.json (you have it right).
- The CM is created in the same namespace as the worker (prefect).
- If you don’t see the update take effect, trigger a worker rollout after the CM is applied:
kubectl rollout restart deploy -n prefect -l <http://app.kubernetes.io/name=prefect-worker|app.kubernetes.io/name=prefect-worker>
- Verify in Prefect UI → Work Pools → kube → Advanced that the base job template now includes the resources block.
Docs for reference:
- Helm charts: prefect-helm
- K8s worker/job template: prefect-kubernetes integrationLoup
11/26/2025, 5:50 PMkubectl logs -n prefect deploy/prefect-worker ─╯
Defaulted container "prefect-worker" out of: prefect-worker, sync-base-job-template (init)
Traceback (most recent call last):
File "/usr/local/lib/python3.11/site-packages/prefect/cli/_utilities.py", line 44, in wrapper
return fn(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/prefect/cli/_types.py", line 159, in sync_fn
return asyncio.run(async_fn(*args, **kwargs))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/asyncio/runners.py", line 190, in run
return runner.run(main)
^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/asyncio/runners.py", line 118, in run
return self._loop.run_until_complete(task)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/asyncio/base_events.py", line 654, in run_until_complete
return future.result()
^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/prefect/cli/worker.py", line 168, in start
await worker.start(
File "/usr/local/lib/python3.11/site-packages/prefect/workers/base.py", line 644, in start
async with self as worker:
File "/usr/local/lib/python3.11/site-packages/prefect_kubernetes/worker.py", line 997, in __aenter__
return await super().__aenter__()
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/prefect/workers/base.py", line 1595, in __aenter__
await self.setup()
File "/usr/local/lib/python3.11/site-packages/prefect/workers/base.py", line 936, in setup
await self.sync_with_backend()
File "/usr/local/lib/python3.11/site-packages/prefect/workers/base.py", line 1114, in sync_with_backend
await self._update_local_work_pool_info()
File "/usr/local/lib/python3.11/site-packages/prefect/workers/base.py", line 1011, in _update_local_work_pool_info
work_pool = await self._client.create_work_pool(work_pool=wp)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/prefect/client/orchestration/_work_pools/client.py", line 478, in create_work_pool
response = await self.request(
^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/prefect/client/orchestration/base.py", line 53, in request
return await self._client.send(request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/prefect/client/base.py", line 379, in send
response.raise_for_status()
File "/usr/local/lib/python3.11/site-packages/prefect/client/base.py", line 163, in raise_for_status
raise PrefectHTTPStatusError.from_httpx_error(exc) from exc.__cause__
prefect.exceptions.PrefectHTTPStatusError: Client error '422 Unprocessable Entity' for url '<http://prefect-server.prefect.svc.cluster.local:4200/api/work_pools/>'
Response: {'exception_message': 'Invalid request received.', 'exception_detail': [{'type': 'value_error', 'loc': ['body', 'base_job_template'], 'msg': 'Value error, The variables specified in the job configuration template must be present as properties in the variables schema. Your job configuration uses the following undeclared variable(s): cpu_request ,memory_request ,cpu_limit ,memory_limit.', 'input': {'variables': {'cpu_request': {'type': 'string', 'default': '500m'}, 'memory_request': {'type': 'string', 'default': '1Gi'}, 'cpu_limit': {'type': 'string', 'default': '1'}, 'memory_limit': {'type': 'string', 'default': '2Gi'}}, 'job_configuration': {'job_manifest': {'spec': {'template': {'spec': {'restartPolicy': 'Never', 'containers': [{'name': 'prefect-job', 'resources': {'requests': {'cpu': '{{ cpu_request }}', 'memory': '{{ memory_request }}'}, 'limits': {'cpu': '{{ cpu_limit }}', 'memory': '{{ memory_limit }}'}}}]}}}}}}, 'ctx': {'error': {}}}], 'request_body': {'name': 'kube', 'type': 'kubernetes', 'base_job_template': {'variables': {'cpu_request': {'type': 'string', 'default': '500m'}, 'memory_request': {'type': 'string', 'default': '1Gi'}, 'cpu_limit': {'type': 'string', 'default': '1'}, 'memory_limit': {'type': 'string', 'default': '2Gi'}}, 'job_configuration': {'job_manifest': {'spec': {'template': {'spec': {'restartPolicy': 'Never', 'containers': [{'name': 'prefect-job', 'resources': {'requests': {'cpu': '{{ cpu_request }}', 'memory': '{{ memory_request }}'}, 'limits': {'cpu': '{{ cpu_limit }}', 'memory': '{{ memory_limit }}'}}}]}}}}}}}}
For more information check: <https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/422>
An exception occurred.
I guess there is something wrong :
apiVersion: v1
kind: ConfigMap
metadata:
name: prefect-base-job-template
namespace: prefect
data:
baseJobTemplate.json: |
{
"variables": {
"cpu_request": { "type": "string", "default": "500m" },
"memory_request": { "type": "string", "default": "1Gi" },
"cpu_limit": { "type": "string", "default": "1" },
"memory_limit": { "type": "string", "default": "2Gi" }
},
"job_configuration": {
"job_manifest": {
"spec": {
"template": {
"spec": {
"restartPolicy": "Never",
"containers": [
{
"name": "prefect-job",
"resources": {
"requests": {
"cpu": "{{ cpu_request }}",
"memory": "{{ memory_request }}"
},
"limits": {
"cpu": "{{ cpu_limit }}",
"memory": "{{ memory_limit }}"
}
}
}
]
}
}
}
}
}
}
We can't merge the default baseJobTemplate.json with my custom one ?Marvin
11/26/2025, 5:51 PMMarvin
11/26/2025, 5:51 PMLoup
11/26/2025, 5:52 PMkubectl logs -n prefect deploy/prefect-worker ─╯
...
return await self._client.send(request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/prefect/client/base.py", line 379, in send
response.raise_for_status()
File "/usr/local/lib/python3.11/site-packages/prefect/client/base.py", line 163, in raise_for_status
raise PrefectHTTPStatusError.from_httpx_error(exc) from exc.__cause__
prefect.exceptions.PrefectHTTPStatusError: Client error '422 Unprocessable Entity' for url '<http://prefect-server.prefect.svc.cluster.local:4200/api/work_pools/>'
Response: {'exception_message': 'Invalid request received.', 'exception_detail': [{'type': 'value_error', 'loc': ['body', 'base_job_template'], 'msg': 'Value error, The variables specified in the job configuration template must be present as properties in the variables schema. Your job configuration uses the following undeclared variable(s): cpu_request ,memory_request ,cpu_limit ,memory_limit.', 'input': {'variables': {'cpu_request': {'type': 'string', 'default': '500m'}, 'memory_request': {'type': 'string', 'default': '1Gi'}, 'cpu_limit': {'type': 'string', 'default': '1'}, 'memory_limit': {'type': 'string', 'default': '2Gi'}}, 'job_configuration': {'job_manifest': {'spec': {'template': {'spec': {'restartPolicy': 'Never', 'containers': [{'name': 'prefect-job', 'resources': {'requests': {'cpu': '{{ cpu_request }}', 'memory': '{{ memory_request }}'}, 'limits': {'cpu': '{{ cpu_limit }}', 'memory': '{{ memory_limit }}'}}}]}}}}}}, 'ctx': {'error': {}}}], 'request_body': {'name': 'kube', 'type': 'kubernetes', 'base_job_template': {'variables': {'cpu_request': {'type': 'string', 'default': '500m'}, 'memory_request': {'type': 'string', 'default': '1Gi'}, 'cpu_limit': {'type': 'string', 'default': '1'}, 'memory_limit': {'type': 'string', 'default': '2Gi'}}, 'job_configuration': {'job_manifest': {'spec': {'template': {'spec': {'restartPolicy': 'Never', 'containers': [{'name': 'prefect-job', 'resources': {'requests': {'cpu': '{{ cpu_request }}', 'memory': '{{ memory_request }}'}, 'limits': {'cpu': '{{ cpu_limit }}', 'memory': '{{ memory_limit }}'}}}]}}}}}}}}
For more information check: <https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/422>
An exception occurred.
We can't merge the default baseJobTemplate.json with my custom one ?Marvin
11/26/2025, 5:52 PMMarvin
11/26/2025, 5:53 PMvariables section must be a JSON Schema object. Right now you’re listing variables directly; Prefect expects them under variables.type = "object" with variables.properties.
Fix your ConfigMap like this:
apiVersion: v1
kind: ConfigMap
metadata:
name: prefect-base-job-template
namespace: prefect
data:
baseJobTemplate.json: |
{
"variables": {
"type": "object",
"properties": {
"cpu_request": { "type": "string", "default": "500m" },
"memory_request": { "type": "string", "default": "1Gi" },
"cpu_limit": { "type": "string", "default": "1" },
"memory_limit": { "type": "string", "default": "2Gi" }
}
},
"job_configuration": {
"job_manifest": {
"spec": {
"template": {
"spec": {
"restartPolicy": "Never",
"containers": [
{
"name": "prefect-job",
"resources": {
"requests": {
"cpu": "{{ cpu_request }}",
"memory": "{{ memory_request }}"
},
"limits": {
"cpu": "{{ cpu_limit }}",
"memory": "{{ memory_limit }}"
}
}
}
]
}
}
}
}
}
}
Why the error happened
- Prefect validates the template and looks for variables via the JSON Schema in variables. Because the schema wrapper (type: object + properties) was missing, it considered cpu_request, memory_request, etc. as “undeclared,” leading to the 422.
About merging with the default template
- There’s no automatic merge with the default. The base job template you provide replaces the default entirely.
- Recommendation: either
- Keep your minimal template like above (fine if you only want to add resources), or
- Start from the default Kubernetes template and add the resources block to the main container to retain all the standard placeholders (image, command, env, labels, namespace, etc.). You can view/edit this in the Work Pool UI’s Advanced section or copy from docs/examples.
Next steps
1) Update the ConfigMap JSON as above and commit.
2) Ensure it’s included in kustomization.yaml (you already did).
3) Let Argo CD sync. If the worker does not roll automatically, force a rollout:
kubectl rollout restart deploy -n prefect -l <http://app.kubernetes.io/name=prefect-worker|app.kubernetes.io/name=prefect-worker>
4) Verify in Prefect UI → Work Pools → your “kube” pool → Advanced that the base job template now shows your resources block.
5) Run a test flow; you can override per-deployment via job_variables as needed.
Helpful references
- Kubernetes worker and base job template docs: prefect-kubernetes integration
- Prefect Helm charts (worker values including baseJobTemplate): prefect-helm
If you’d like, I can also give you a “default template + resources added” JSON to drop in, so you keep all the standard fields and just layer in CPU/memory.Loup
11/26/2025, 5:59 PMbaseJobTemplate.json everything is broken. When I run a prefect flow :
Worker 'KubernetesWorker b0b8a87a-3574-4925-9b4c-c4b567667609' submitting flow run '5f94d935-4b59-4294-aa34-aef53595d5f6'
06:57:39 PM
prefect.flow_runs.worker
Failed to submit flow run '5f94d935-4b59-4294-aa34-aef53595d5f6' to infrastructure.
Traceback (most recent call last):
File "/usr/local/lib/python3.11/site-packages/prefect/workers/base.py", line 1284, in _submit_run_and_capture_errors
configuration = await self._get_configuration(flow_run)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/prefect/workers/base.py", line 1395, in _get_configuration
configuration = await self.job_configuration.from_template_and_values(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/prefect/client/utilities.py", line 99, in with_injected_client
return await fn(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/prefect/workers/base.py", line 208, in from_template_and_values
return cls(**populated_configuration)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/pydantic/main.py", line 250, in __init__
validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pydantic_core._pydantic_core.ValidationError: 1 validation error for KubernetesWorkerJobConfiguration
Value error, Job is missing required attributes at the following paths: /apiVersion, /kind, /spec/template/spec/completions, /spec/template/spec/parallelism [type=value_error, input_value={'job_manifest': {'spec':...artPolicy': 'Never'}}}}}, input_type=dict]
For further information visit <https://errors.pydantic.dev/2.12/v/value_error>
06:57:39 PM
prefect.flow_runs.worker
Reported flow run '5f94d935-4b59-4294-aa34-aef53595d5f6' as crashed: Flow run could not be submitted to infrastructure:
1 validation error for KubernetesWorkerJobConfiguration
Value error, Job is missing required attributes at the following paths: /apiVersion, /kind, /spec/template/spec/completions, /spec/template/spec/parallelism [type=value_error, input_value={'job_manifest': {'spec':...artPolicy': 'Never'}}}}}, input_type=dict]
For further information visit <https://errors.pydantic.dev/2.12/v/value_error>Marvin
11/26/2025, 5:59 PMMarvin
11/26/2025, 6:01 PMMarvin
11/26/2025, 6:01 PMOption B — Start from Prefect’s default and add resources
If you prefer to keep everything the worker ships with, copy the default base job template from your Work Pool UI (Advanced → Base job template → “View JSON”), paste it into the ConfigMap, then add this `resources` block to the main `prefect-job` container and add the four variables to the `variables.properties`:
"resources": {
"requests": {
"cpu": "{{ cpu_request }}",
"memory": "{{ memory_request }}"
},
"limits": {
"cpu": "{{ cpu_limit }}",
"memory": "{{ memory_limit }}"
}
}
After updating
- Commit and let Argo CD sync.
- Restart the worker so it re-syncs the base template:
kubectl rollout restart deploy -n prefect -l app.kubernetes.io/name=prefect-worker
```
- In the UI: Work Pools → your pool → Advanced → confirm the template includes apiVersion/kind/parallelism/completions and your resources.
Why the previous error happened
- Prefect validates the job manifest against a model that requires:
- apiVersion: batch/v1
- kind: Job
- spec.template.spec.parallelism (int)
- spec.template.spec.completions (int)
- restartPolicy: Never
- A container named prefect-job with image/args/env placeholders
- Your earlier minimal template omitted those, so it failed validation.
If you want, paste your current JSON and I’ll patch it to be valid.Loup
11/26/2025, 6:20 PMapiVersion: v1
kind: ConfigMap
metadata:
name: prefect-base-job-template
namespace: prefect
data:
baseJobTemplate.json: |
{
"variables": {
"type": "object",
"properties": {
"env": {
"type": "object",
"title": "Environment Variables",
"description": "Environment variables to set when starting a flow run.",
"additionalProperties": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
}
},
"name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Name",
"default": null,
"description": "Name given to infrastructure created by a worker."
},
"image": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Image",
"default": null,
"examples": [
"<http://docker.io/prefecthq/prefect:3-latest|docker.io/prefecthq/prefect:3-latest>"
],
"description": "The image reference of a container image to use for created jobs. If not set, the latest Prefect image will be used."
},
"labels": {
"type": "object",
"title": "Labels",
"description": "Labels applied to infrastructure created by a worker.",
"additionalProperties": {
"type": "string"
}
},
"command": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Command",
"default": null,
"description": "The command to use when starting a flow run. In most cases, this should be left blank and the command will be automatically generated by the worker."
},
"namespace": {
"type": "string",
"title": "Namespace",
"default": "prefect",
"description": "The Kubernetes namespace to create jobs within."
},
"backoff_limit": {
"type": "integer",
"title": "Backoff Limit",
"default": 0,
"minimum": 0,
"description": "The number of times Kubernetes will retry a job after pod eviction. If set to 0, Prefect will reschedule the flow run when the pod is evicted unless PREFECT_FLOW_RUN_EXECUTE_SIGTERM_BEHAVIOR is set to value different from 'reschedule'."
},
"stream_output": {
"type": "boolean",
"title": "Stream Output",
"default": true,
"description": "If set, output will be streamed from the job to local standard output."
},
"cluster_config": {
"anyOf": [
{
"$ref": "#/definitions/KubernetesClusterConfig"
},
{
"type": "null"
}
],
"default": null,
"description": "The Kubernetes cluster config to use for job creation."
},
"finished_job_ttl": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"title": "Finished Job TTL",
"default": null,
"description": "The number of seconds to retain jobs after completion. If set, finished jobs will be cleaned up by Kubernetes after the given delay. If not set, jobs will be retained indefinitely."
},
"image_pull_policy": {
"enum": [
"IfNotPresent",
"Always",
"Never"
],
"type": "string",
"title": "Image Pull Policy",
"default": "IfNotPresent",
"description": "The Kubernetes image pull policy to use for job containers."
},
"service_account_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Service Account Name",
"default": null,
"description": "The Kubernetes service account to use for job creation."
},
"job_watch_timeout_seconds": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"title": "Job Watch Timeout Seconds",
"default": null,
"description": "Number of seconds to wait for each event emitted by a job before timing out. If not set, the worker will wait for each event indefinitely."
},
"pod_watch_timeout_seconds": {
"type": "integer",
"title": "Pod Watch Timeout Seconds",
"default": 60,
"description": "Number of seconds to watch for pod creation before timing out."
},
"cpu_request": {
"type": "string",
"title": "CPU Request",
"default": "500m",
"description": "The requested CPU for the job."
},
"memory_request": {
"type": "string",
"title": "Memory Request",
"default": "1Gi",
"description": "The requested memory for the job."
},
"cpu_limit": {
"type": "string",
"title": "CPU Limit",
"default": "1",
"description": "The CPU limit for the job."
},
"memory_limit": {
"type": "string",
"title": "Memory Limit",
"default": "2Gi",
"description": "The memory limit for the job."
}
},
"definitions": {
"KubernetesClusterConfig": {
"type": "object",
"title": "KubernetesClusterConfig",
"required": [
"config",
"context_name"
],
"properties": {
"config": {
"type": "object",
"title": "Config",
"description": "The entire contents of a kubectl config file.",
"additionalProperties": true
},
"context_name": {
"type": "string",
"title": "Context Name",
"description": "The name of the kubectl context to use."
}
},
"description": "Stores configuration for interaction with Kubernetes clusters.\n\nSee `from_file` for creation.",
"secret_fields": [],
"block_type_slug": "kubernetes-cluster-config",
"block_schema_references": {}
}
},
"description": "Default variables for the Kubernetes worker.\n\nThe schema for this class is used to populate the `variables` section of the default\nbase job template."
},
"job_configuration": {
"env": "{{ env }}",
"name": "{{ name }}",
"labels": "{{ labels }}",
"command": "{{ command }}",
"namespace": "{{ namespace }}",
"job_manifest": {
"kind": "Job",
"spec": {
"template": {
"spec": {
"containers": [
{
"env": "{{ env }}",
"args": "{{ command }}",
"name": "prefect-job",
"image": "{{ image }}",
"imagePullPolicy": "{{ image_pull_policy }}",
"resources": {
"requests": {
"cpu": "{{ cpu_request }}",
"memory": "{{ memory_request }}"
},
"limits": {
"cpu": "{{ cpu_limit }}",
"memory": "{{ memory_limit }}"
}
}
}
],
"completions": 1,
"parallelism": 1,
"restartPolicy": "Never",
"serviceAccountName": "{{ service_account_name }}"
}
},
"backoffLimit": "{{ backoff_limit }}",
"ttlSecondsAfterFinished": "{{ finished_job_ttl }}"
},
"metadata": {
"labels": "{{ labels }}",
"namespace": "{{ namespace }}",
"generateName": "{{ name }}-"
},
"apiVersion": "batch/v1"
},
"stream_output": "{{ stream_output }}",
"cluster_config": "{{ cluster_config }}",
"job_watch_timeout_seconds": "{{ job_watch_timeout_seconds }}",
"pod_watch_timeout_seconds": "{{ pod_watch_timeout_seconds }}"
}
}
So I can use it with ?
- name: sync_typesense
version: 1.0.0
tags:
- typesense
description: Sync all Typesense collections (movies, tv_series, persons, playlists, users)
entrypoint: sync_typesense/sync_typesense.py:sync_typesense
parameters: {}
work_pool:
name: kube
job_variables:
<<: *job_variables
memory_request: "8Gi"
cpu_request: "2"
memory_limit: "8Gi"
cpu_limit: "4"Marvin
11/26/2025, 6:20 PM