kubernetes/kops · error

unable to parse disk source URL: %q

Error message

unable to parse disk source URL: %q

What it means

In Instance.Find, for attached (non-boot) disks whose source is not the instance's own project/zone path, kOps parses the disk source URL with gce.ParseGoogleCloudURL. This error is thrown when that URL cannot be parsed into its project/zone/name components, so the disk reference cannot be reconstructed in the actual state.

Source

Thrown at upup/pkg/fi/cloudup/gcetasks/instance.go:134

			// TODO: Parse source URL instead of assuming same project/zone?
			name := lastComponent(source)
			d, err := cloud.Compute().Disks().Get(cloud.Project(), *e.Zone, name)
			if err != nil {
				if gce.IsNotFound(err) {
					return nil, fmt.Errorf("disk not found %q: %v", source, err)
				}
				return nil, fmt.Errorf("error querying for disk %q: %v", source, err)
			}

			image, err := ShortenImageURL(cloud.Project(), d.SourceImage)
			if err != nil {
				return nil, fmt.Errorf("error parsing source image URL: %v", err)
			}
			actual.Image = new(image)
		} else {
			url, err := gce.ParseGoogleCloudURL(disk.Source)
			if err != nil {
				return nil, fmt.Errorf("unable to parse disk source URL: %q", disk.Source)
			}

			actual.Disks[disk.DeviceName] = &Disk{Name: &url.Name}
		}
	}

	if r.Metadata != nil {
		actual.Metadata = make(map[string]fi.Resource)
		for _, i := range r.Metadata.Items {
			actual.Metadata[i.Key] = fi.NewStringResource(fi.ValueOf(i.Value))
		}
		actual.metadataFingerprint = r.Metadata.Fingerprint
	}

	return actual, nil
}

func (e *Instance) Run(c *fi.CloudupContext) error {

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Print/inspect the instance's disk source: `gcloud compute instances describe <name> --zone=<zone> --format='value(disks[].source)'` and compare to what ParseGoogleCloudURL expects (full https://.../zones/<zone>/disks/<name> URL)
  2. Re-attach the disk using its canonical full source URL
  3. Update or remove the stale disk reference in the kops spec/state

Example fix

// before
Disks().Insert(...).Source("my-disk")
// after
Disks().Insert(...).Source("https://www.googleapis.com/compute/v1/projects/<proj>/zones/<zone>/disks/my-disk")
Defensive patterns

Strategy: validation

Validate before calling

// Ensure every attached disk source is a canonical full URL before Find
func canonicalDiskSource(src string) bool {
	u := url.ParseOrEmpty(src)
	return strings.HasSuffix(u.Path, "/disks/") && u.Name != "" && strings.Contains(u.Path, "/zones/")
}

Type guard

func isParseableGCEURL(src string) bool {
	_, err := gce.ParseGoogleCloudURL(src)
	return err == nil
}

Prevention

When it happens

Trigger: disk.Source doesn't match the Google Cloud URL pattern expected by ParseGoogleCloudURL (e.g. truncated URL, regional/multi-region disk paths, custom formats, or manually attached disks with non-standard source strings).

Common situations: Manually attaching disks via API with shortened names instead of full URLs; disks attached from other regions with URL shapes the parser doesn't accept; drift where the instance's disk source changed after cluster creation.

Understand the failure class

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/276d589204950ad9. Report an issue: GitHub.