docker/cli · error

invalid credential spec: value must be prefixed with…

Error message

invalid credential spec: value must be prefixed with "config://", "file://", or "registry://"

What it means

The `--credential-spec` flag (Windows-only, for managed service accounts) requires a URL-scheme prefix to identify the credential source. The `credentialSpecOpt.Set` method at opts.go:362-403 parses the scheme via `strings.Cut(value, "://")` and accepts `config://`, `file://`, or `registry://`. An empty string is valid (used to clear the spec during updates, line 365-371). Any non-empty value that does not start with one of the three valid schemes hits the `default` case at line 400-402.

Solutions

  1. For Docker config-based specs: prefix with `config://`, e.g., `--credential-spec config://myconfig`
  2. For file-based specs: prefix with `file://`, e.g., `--credential-spec file://C:/path/spec.json`
  3. For registry-based specs: prefix with `registry://`, e.g., `--credential-spec registry://fabric/MyServiceAccount`
  4. To clear an existing spec on update: pass `--credential-spec ""` (empty string)

Example fix

# before
docker service create --credential-spec myconfig --image myimage web
# error: invalid credential spec: value must be prefixed with ...

# after (Docker config)
docker service create --credential-spec config://myconfig --image myimage web

# after (file path)
docker service create --credential-spec file://C:/spec.json --image myimage web
Defensive patterns

Strategy: validation

Validate before calling

// Validate credential spec before calling Set
func validateCredentialSpec(value string) error {
    if value == "" {
        return nil // empty is valid (clears spec on update)
    }
    scheme, _, ok := strings.Cut(value, "://")
    if !ok {
        return errors.New(`value must be prefixed with "config://", "file://", or "registry://"`)
    }
    switch credentialSpecType(scheme) {
    case credentialSpecConfig, credentialSpecFile, credentialSpecRegistry:
        return nil
    default:
        return errors.New(`invalid credential spec scheme: ` + scheme)
    }
}

Prevention

When it happens

Trigger: Passing `--credential-spec myconfig` (no scheme), `--credential-spec C:\path\to\spec.json` (bare file path without `file://` prefix), or `--credential-spec configs/myconfig` (Docker config name without `config://` prefix).

Common situations: A Windows shop migrating from `docker run --credential-spec` confuses the flag value format. The developer passes the config name or file path directly without the required URL scheme prefix.

Related errors


AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07). Data as JSON: /api/errors/434314a7389a98b2. Report an issue: GitHub.

Appendix: source

Thrown at cli/command/service/opts.go:402

		// Therefore, this isn't the definitive location for the value of
		// Config that is passed to the API.
		c.value = &swarm.CredentialSpec{
			Config: val,
		}
		return nil
	case credentialSpecFile:
		c.value = &swarm.CredentialSpec{
			File: val,
		}
		return nil
	case credentialSpecRegistry:
		c.value = &swarm.CredentialSpec{
			Registry: val,
		}
		return nil
	default:
		c.value = &swarm.CredentialSpec{}
		return errors.New(`invalid credential spec: value must be prefixed with "config://", "file://", or "registry://"`)
	}
}

func (*credentialSpecOpt) Type() string {
	return "credential-spec"
}

func (c *credentialSpecOpt) String() string {
	return c.source
}

func (c *credentialSpecOpt) Value() *swarm.CredentialSpec {
	return c.value
}

func resolveNetworkID(ctx context.Context, apiClient client.NetworkAPIClient, networkIDOrName string) (string, error) {
	res, err := apiClient.NetworkInspect(ctx, networkIDOrName, client.NetworkInspectOptions{Scope: "swarm"})
	if err != nil {

View on GitHub (pinned to 4f84911bfe)