hashicorp/nomad · error

unknown service registration provider for update: %q

Error message

unknown service registration provider for update: %q

What it means

When a service changes providers between the old and new registration (old provider != new provider), the wrapper first removes via the old provider, then registers via the new one, dispatching UpdateWorkload on the new provider. This error is returned when the NEW provider string is neither "nomad" nor "consul", so no backend can handle the update.

Source

Thrown at client/serviceregistration/wrapper/wrapper.go:123

	// Hot path to exit if there is nothing to do.
	if len(old.Services) == 0 && len(new.Services) == 0 {
		return nil
	}

	newProvider := new.RegistrationProvider()
	oldProvider := old.RegistrationProvider()

	// If the new and old services use the same provider, call the
	// UpdateWorkload and leave it at that.
	if newProvider == oldProvider {
		switch newProvider {
		case structs.ServiceProviderNomad:
			return h.nomadServiceProvider.UpdateWorkload(old, new)
		case structs.ServiceProviderConsul:
			return h.consulServiceProvider.UpdateWorkload(old, new)
		default:
			return fmt.Errorf("unknown service registration provider for update: %q", newProvider)
		}
	}

	// If we have new services, call the relevant provider. Registering can
	// return an error. Do this before RemoveWorkload, so we can halt the
	// process if needed, otherwise we may leave the task/group
	// registration-less.
	if len(new.Services) > 0 {
		if err := h.RegisterWorkload(new); err != nil {
			return err
		}
	}

	if len(old.Services) > 0 {
		h.RemoveWorkload(old)
	}

	return nil

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Correct the new provider value in the job to "nomad" or "consul"
  2. Re-submit the job through validation so unknown providers are rejected before update
  3. Align Nomad client version with the version that understands the provider in the spec

Example fix

// before
service {
  name = "web"
  provider = "hashicorp"
}
// after
service {
  name = "web"
  provider = "nomad"
}
Defensive patterns

Strategy: validation

Validate before calling

if newProvider != oldProvider && !knownProvider(newProvider) {
    return fmt.Errorf("provider change %q -> %q rejected: target provider unknown", oldProvider, newProvider)
}

Type guard

func canHandleUpdate(oldP, newP string) bool {
    return knownProvider(newP) && knownProvider(oldP)
}

Try / catch

err := wrapper.UpdateWorkload(old, new)
if err != nil && strings.Contains(err.Error(), "unknown service registration provider for update") {
    logger.Error("provider switch to unknown backend", "old", old.Provider, "new", new.Provider)
    return err
}

Prevention

When it happens

Trigger: UpdateWorkload detects oldProvider != newProvider and switches to the switch on newProvider; newProvider has an unrecognized value (empty string, typo, or provider from a newer Nomad version unknown to this client), raised from Update/preRunLocked paths.

Common situations: Editing a job to change provider but with a typo'd target value; job spec produced by tooling that emits an unsupported provider; version skew where a job built for a newer Nomad is applied to an older client.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/26b56d6d0c50d5eb. Report an issue: GitHub.