Repository: argoproj/argo-rollouts (2025-06-04T15:05:12Z)

Issue:
Job's label value exceeds max value of 63 characters.
## Summary 
Assume we have created an analysis template as below:
```
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: service-endpoint-reachable
spec:
  args:
  - name: service-fqdn
  - name: status-code
  metrics:
  - name: service-endpoint-reachable
    provider:
      job:
        spec:
          backoffLimit: 1
          template:
            spec:
              restartPolicy: Never
              containers:
                - name: curl-service-endpoint
                  image: curlimages/curl:7.73.0
                  command:
                    - /bin/sh
                    - -c
                    - |
                      curl -I {{args.service-fqdn}}
                      status_code=$(curl --write-out "%{http_code}\n" --silent --output /dev/null "{{args.service-fqdn}}");
                      [ $status_code -eq {{args.status-code}} ]
```
argo rollout will failed to create the wanted job due to the limit of max label value length(63) in kubernetes.
```
 message: 'Job.batch "990a01d4-ff15-402b-8516-0914c420e2b2.service-endpoint-reachable.5"
        is invalid: spec.template.labels: Invalid value: "990a01d4-ff15-402b-8516-0914c420e2b2.service-endpoint-reachable.5":
        must be no more than 63 characters'
```
I guess this is a known issue [1], but it's very likely to happen, due to the generation style.
[1]: https://github.com/argoproj/argo-rollouts/blob/a98a2742e522549a660e1de20b7b7c08dcc6884a/metricproviders/job/job.go#L57

## Diagnostics

What version of Argo Rollouts are you running?

```
# Paste the logs from the rollout controller

# Logs for the entire controller:
kubectl logs -n argo-rollouts deployment/argo-rollouts

# Logs for a specific rollout:
kubectl logs -n argo-rollouts deployment/argo-rollouts | grep rollout=<ROLLOUTNAME>
```

---
<!-- Issue Author: Don't delete this message to encourage other users to support your issue! -->
**Message from the maintainers**:

Impacted by this bug? Give it a 👍. We prioritize the issues with the most 👍.


Discussion:
I'm running into this issue as well. As a user of argo-rollouts, I'd like my attempts to create [Cluster]AnalysisTemplate with metric names that are too long to fail at creation time instead of failing later at AnalysisRun run-time. Perhaps the code @TommyLike referenced above can check the Job name length and hash or truncate the provided name in some way?

https://github.com/argoproj/argo-rollouts/blob/96ba0302f4d904e9aba36c3341025f4f51eaed81/metricproviders/job/job.go#L57-L63
As a workaround for this issue, I have truncated all my job names to be 20 characters or less, because that's how many characters it was over in my case.  I don't know if the length is variable in what is generated here or not by Argo Rollouts, but I haven't had the issue since.  I would assume it's only variable if the number of jobs in the analysistemplate is double-digits or greater, as I would expect the UUID to be of fixed length that seems to be prepended to this label.
This issue is stale because it has been open 60 days with no activity.
It is unacceptable for this issue to be stale. It persists still. If you are using labels to find the child job you should break this up and use multiple labels.
What would be the recommended solution here? Simply truncating the name would seem to be the quickest workaround, but then we run the danger of having different jobs getting truncated to the same name. Or this is a not a possible/interesting use case?
facing same issue 
also impacted by this



Patch:
diff --git a/metricproviders/job/job.go b/metricproviders/job/job.go
index 5a85c5c71e..b7ae868554 100644
--- a/metricproviders/job/job.go
+++ b/metricproviders/job/job.go
@@ -17,6 +17,7 @@ import (
 
 	"github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1"
 	analysisutil "github.com/argoproj/argo-rollouts/utils/analysis"
+	"github.com/argoproj/argo-rollouts/utils/defaults"
 	metricutil "github.com/argoproj/argo-rollouts/utils/metric"
 	timeutil "github.com/argoproj/argo-rollouts/utils/time"
 )
@@ -73,8 +74,19 @@ func (p *JobProvider) GetMetadata(metric v1alpha1.Metric) map[string]string {
 // fit into a 63 character label, since the k8s job controller incorporates the job name into the
 // pod spec labels.
 func newJobName(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) string {
+
 	jobID := getJobIDSuffix(run, metric.Name)
-	return fmt.Sprintf("%s.%s.%d", run.UID, metric.Name, jobID)
+	jobName := fmt.Sprintf("%s.%s.%d", run.UID, metric.Name, jobID)
+
+	// Kubernetes can accept this job name without any issues
+	if len(jobName) <= defaults.Kubernetes_DNS_Limit {
+		return jobName
+	}
+
+	//We are over 63 characters so Kubernetes will reject this job name. We need to truncate it to 63 characters.
+	charactersOverLimit := len(jobName) - defaults.Kubernetes_DNS_Limit
+	truncateTo := len(metric.Name) - charactersOverLimit
+	return fmt.Sprintf("%s.%s.%d", run.UID, metric.Name[:truncateTo], jobID)
 }
 
 // getJobIDSuffix returns a numeric id which will be used as part of the job name. This is equal
diff --git a/utils/defaults/defaults.go b/utils/defaults/defaults.go
index f1c38dcef1..28431a4489 100644
--- a/utils/defaults/defaults.go
+++ b/utils/defaults/defaults.go
@@ -50,6 +50,8 @@ const (
 	DefaultRolloutPluginFolder = "plugin-bin"
 	// DefaultDescribeTagsLimit is the default number resources (ARNs) in a single call
 	DefaultDescribeTagsLimit int = 20
+	// Kubernetes_DNS_Limit is the maximum length of a DNS name in Kubernetes. Currently used for Analysis Job names
+	Kubernetes_DNS_Limit int = 63
 )
 
 const (


Test patch:
diff --git a/metricproviders/job/job_test.go b/metricproviders/job/job_test.go
index eb7a6a1629..67e34593f3 100644
--- a/metricproviders/job/job_test.go
+++ b/metricproviders/job/job_test.go
@@ -21,6 +21,7 @@ import (
 	"k8s.io/client-go/tools/cache"
 
 	"github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1"
+	"github.com/argoproj/argo-rollouts/utils/defaults"
 )
 
 var noResyncPeriodFunc = func() time.Duration { return 0 }
@@ -324,3 +325,75 @@ func TestGarbageCollect(t *testing.T) {
 		}
 	}
 }
+
+func TestJobNameWithin63characters(t *testing.T) {
+	ctx := context.Background()
+	p := newTestJobProvider()
+	run := newRunWithJobMetric()
+
+	// Set the UID to a realistic value
+	run.UID = types.UID("34e4d823-4ba9-4afe-8775-6384561d7ef3")
+
+	// Create a metric with a short name that is within 63 characters (Kubernetes JOB DNS restriction)
+	shortMetricName := "short-job-name"
+	run.Spec.Metrics[0].Name = shortMetricName
+	metric := run.Spec.Metrics[0]
+
+	// First measurement
+	measurement := p.Run(run, metric)
+	expectedName := fmt.Sprintf("%s.%s.1", run.UID, metric.Name)
+	assert.Equal(t, expectedName, measurement.Metadata[JobNameKey], "Job name should not be truncated")
+
+	// Ensure the job was created with the correct name
+	jobs, err := p.kubeclientset.BatchV1().Jobs(run.Namespace).List(ctx, metav1.ListOptions{})
+	assert.NoError(t, err)
+	assert.Equal(t, expectedName, jobs.Items[0].Name, "Job name should match the expected name")
+
+	// Verify that the job name is less than or equal to 63 characters
+	assert.LessOrEqual(t, len(jobs.Items[0].Name), defaults.Kubernetes_DNS_Limit, "Job name should be less than or equal to 63 characters")
+}
+
+func TestJobNameWithTruncation(t *testing.T) {
+	ctx := context.Background()
+	p := newTestJobProvider()
+	run := newRunWithJobMetric()
+
+	// Set the UID to a realistic value
+	run.UID = types.UID("5d610152-d78d-4af9-aa6a-81c227ea422c")
+
+	// Create a metric where the name itself is within limits, but it is larger than 63 characters if the UUID is included
+	longMetricName := "service-endpoint-reachable"
+	run.Spec.Metrics[0].Name = longMetricName
+	metric := run.Spec.Metrics[0]
+
+	// First measurement
+	measurement := p.Run(run, metric)
+	assert.Len(t, measurement.Metadata[JobNameKey], defaults.Kubernetes_DNS_Limit, "Job name should be truncated to 63 characters")
+
+	// Ensure that job is submitted
+	_, err := p.kubeclientset.BatchV1().Jobs(run.Namespace).List(ctx, metav1.ListOptions{})
+	assert.NoError(t, err)
+}
+
+func TestLongJobName(t *testing.T) {
+	ctx := context.Background()
+	p := newTestJobProvider()
+	run := newRunWithJobMetric()
+
+	// Set the UID to a realistic value
+	run.UID = types.UID("a3f5c9b2-1d4e-4b8a-9f3e-2c7d8e6a4b1c")
+
+	// Create a metric with a long name (70 characters) that is obviously longer than 63 characters
+	longMetricName := "this-is-a-very-long-metric-name-that-is-exactly-seventy-characters-long"
+	run.Spec.Metrics[0].Name = longMetricName
+	metric := run.Spec.Metrics[0]
+
+	// First measurement
+	measurement := p.Run(run, metric)
+	assert.Len(t, measurement.Metadata[JobNameKey], defaults.Kubernetes_DNS_Limit, "Job name should be truncated to 63 characters")
+
+	// Ensure that job is submitted
+	_, err := p.kubeclientset.BatchV1().Jobs(run.Namespace).List(ctx, metav1.ListOptions{})
+	assert.NoError(t, err)
+
+}