GoogleContainerTools/skaffold · error

StatusCode_DEPLOY_READ_MANIFEST_ERR

StatusCode_DEPLOY_READ_MANIFEST_ERR

Error message

unable to unmarshal Cloud Run Service config: %w

What it means

During cleanup, deleteRunService unmarshals each rendered Cloud Run Service manifest into run.Service. If k8syaml.Unmarshal fails (malformed YAML or fields incompatible with run.Service), the service cannot be deleted and DEPLOY_READ_MANIFEST_ERR is returned, aborting cleanup of that resource.

Source

Thrown at pkg/skaffold/deploy/cloudrun/deploy.go:526

			}
		case tpe == typeWorkerPool:
			err := d.deleteRunWorkerPool(crclient, out, dryRun, manifest)
			if err != nil {
				errors = append(errors, err)
			}
		}
	}
	if len(errors) != 0 {
		// TODO: is there a good way to report all of the errors?
		return errors[0]
	}
	return nil
}

func (d *Deployer) deleteRunService(crclient *run.APIService, out io.Writer, dryRun bool, manifest []byte) error {
	service := &run.Service{}
	if err := k8syaml.Unmarshal(manifest, service); err != nil {
		return sErrors.NewError(fmt.Errorf("unable to unmarshal Cloud Run Service config: %w", err), &proto.ActionableErr{
			Message: err.Error(),
			ErrCode: proto.StatusCode_DEPLOY_READ_MANIFEST_ERR,
		})
	}

	var projectID string
	switch {
	case d.Project != "":
		projectID = d.Project
	case service.Metadata.Namespace != "":
		projectID = service.Metadata.Namespace
	default:
		// no project specified, we don't know what to delete.
		return sErrors.NewError(fmt.Errorf("unable to determine Google Cloud Project"), &proto.ActionableErr{
			Message: "No Google Cloud Project found in Cloud Run manifest or Skaffold Manifest.",
			ErrCode: proto.StatusCode_DEPLOY_READ_MANIFEST_ERR,
		})
	}

View on GitHub (pinned to a1189de023)

Solutions

  1. Re-render the manifests (`skaffold render`) to regenerate clean output and clear stale state
  2. Validate the YAML syntax and fix indentation/typing issues
  3. Ensure the manifest is a Cloud Run Service (kind: Service, run.googleapis.com) matching the v1 schema
  4. Manually delete the resource with `gcloud run services delete` if cleanup remains blocked

Example fix

// before (ports typed wrong)
containers:
- image: img:latest
  ports: "8080"
// after
containers:
- image: img:latest
  ports:
  - containerPort: 8080
Defensive patterns

Strategy: validation

Validate before calling

func validateServiceManifest(manifest []byte) error {
    var m map[string]interface{}
    if err := yaml.Unmarshal(manifest, &m); err != nil {
        return fmt.Errorf("invalid YAML: %w", err)
    }
    if m["kind"] != "Service" {
        return fmt.Errorf("expected kind Service, got %v", m["kind"])
    }
    return nil
}

Type guard

func isCloudRunService(m map[string]interface{}) bool {
    kind, _ := m["kind"].(string)
    return kind == "Service"
}

Try / catch

err := deployer.Cleanup(ctx, out)
if err != nil {
    var actionErr *sErrors.Error
    if errors.As(err, &actionErr) && actionErr.ErrCode == proto.StatusCode_DEPLOY_READ_MANIFEST_ERR {
        // re-render manifests or fall back to `gcloud run services delete`
    }
    return err
}

Prevention

When it happens

Trigger: deleteRunService calls k8syaml.Unmarshal(manifest, service) on manifests fetched from skaffold's rendered output or a stored Cloud Run state file that is corrupted, truncated, or has wrong-typed fields for run.Service.

Common situations: Corrupted/truncated rendered-manifests cache between runs; a manifest edited after render; wrong kind captured for a Service slot; schema drift causing type mismatches (e.g. ports as strings).

Related errors


AI-assisted analysis of GoogleContainerTools/skaffold@a1189de023 (2026-09-05). Data as JSON: /api/errors/b22aa550e9d9844b. Report an issue: GitHub.