docker/cli · error

archive format is invalid

Error message

archive format is invalid

What it means

Returned by importEndpointTLS when a TLS file path inside an archive, after stripping the 'tls/' prefix, does not split into exactly two parts (endpointName/fileName). Docker context TLS data must be stored as tls/{endpointName}/{fileName}; any other depth is rejected.

Solutions

  1. Re-export the context with docker context export so the tls/endpoint/file layout is preserved.
  2. Repackage the archive so every TLS entry matches the pattern tls/<endpointName>/<fileName> (exactly two path segments after tls/).
  3. Remove misplaced TLS entries from the archive before importing.

Example fix

// before: archive has tls/cert.pem (flat, invalid)
// after:  archive must have tls/docker/cert.pem and tls/docker/key.pem
//         mkdir -p tls/docker && mv tls/cert.pem tls/docker/
Defensive patterns

Strategy: validation

Validate before calling

// Validate every tls/ entry has exactly endpoint/file structure
func validateTLSEntries(names []string) error {
	for _, n := range names {
		if !strings.HasPrefix(n, "tls/") { continue }
		parts := strings.SplitN(strings.TrimPrefix(n, "tls/"), "/", 2)
		if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
			return fmt.Errorf("archive format is invalid for %s", n)
		}
	}
	return nil
}

Prevention

When it happens

Trigger: An imported archive contains a TLS entry whose path is 'tls/cert.pem' (only one segment) or 'tls/a/b/c.pem' (three segments) instead of the required 'tls/{endpoint}/{file}' two-level structure.

Common situations: Manually archiving TLS files flat under tls/ without an endpoint subdirectory; merging two endpoints into one nested path; a tar/zip created by a non-Docker tool that flattens or re-nests the directory layout.

Related errors


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

Appendix: source

Thrown at cli/context/store/store.go:515

func parseMetadata(data []byte, name string) (Metadata, error) {
	var meta Metadata
	if err := json.Unmarshal(data, &meta); err != nil {
		return meta, err
	}
	if err := ValidateContextName(name); err != nil {
		return Metadata{}, err
	}
	meta.Name = name
	return meta, nil
}

func importEndpointTLS(tlsData *ContextTLSData, tlsPath string, data []byte) error {
	parts := strings.SplitN(strings.TrimPrefix(tlsPath, "tls/"), "/", 2)
	if len(parts) != 2 {
		// TLS endpoints require archived file directory with 2 layers
		// i.e. tls/{endpointName}/{fileName}
		return errors.New("archive format is invalid")
	}

	epName := parts[0]
	fileName := parts[1]
	if _, ok := tlsData.Endpoints[epName]; !ok {
		tlsData.Endpoints[epName] = EndpointTLSData{
			Files: map[string][]byte{},
		}
	}
	tlsData.Endpoints[epName].Files[fileName] = data
	return nil
}

type contextdir string

func contextdirOf(name string) contextdir {
	return contextdir(digest.FromString(name).Encoded())
}

View on GitHub (pinned to 4f84911bfe)