gastownhall/beads · error

oci:// URL must include a namespace or bucket host

Error message

oci:// URL must include a namespace or bucket host

What it means

oci:// URLs must include a namespace or bucket host (e.g. oci://namespace/bucket/path). An empty parsed.Host means the registry namespace/bucket portion is missing, so the object store location is unresolvable.

Source

Thrown at internal/remotecache/url.go:166

			return fmt.Errorf("%s:// URL must include a hostname", scheme)
		}
	case "ssh", "git", "git+ssh":
		if parsed.Host == "" {
			return fmt.Errorf("%s:// URL must include a hostname", scheme)
		}
	case "s3", "aws", "gs":
		// s3://bucket/path, aws://bucket/path, gs://bucket/path — host is the bucket
		if parsed.Host == "" {
			return fmt.Errorf("%s:// URL must include a bucket name", scheme)
		}
	case "az":
		// az://account.blob.core.windows.net/container/path
		if parsed.Host == "" {
			return fmt.Errorf("az:// URL must include a storage account hostname")
		}
	case "oci":
		if parsed.Host == "" {
			return fmt.Errorf("oci:// URL must include a namespace or bucket host")
		}
	case "file":
		// file:// is allowed with any path
	case "git+file":
		// git+file:// is Dolt's normalized form for local git remotes.
	}

	return nil
}

// validateSCPURL validates an SCP-style URL (user@host:path)
func validateSCPURL(rawURL string) error {
	// Already matched gitSSHPattern, so structure is valid.
	// Extract host and verify no control chars (already checked above).
	atIdx := strings.Index(rawURL, "@")
	colonIdx := strings.Index(rawURL[atIdx:], ":")
	if atIdx < 0 || colonIdx < 0 {
		return fmt.Errorf("SCP-style URL must be in user@host:path format")

View on GitHub (pinned to 71377f2769)

Solutions

  1. Add the namespace/bucket host: "oci://my-namespace/my-bucket/path"
  2. Check OCI_NAMESPACE / bucket config substitution is non-empty
  3. Match the object-storage layout used by your OCI provider (namespace first, then bucket)

Example fix

// before
remote := "oci:///my-bucket/db"
// after
remote := "oci://my-namespace/my-bucket/db"
Defensive patterns

Strategy: validation

Validate before calling

func validOCIURL(u string) bool {
	rest, ok := strings.CutPrefix(u, "oci://")
	if !ok { return false }
	host := rest
	if i := strings.Index(rest, "/"); i >= 0 { host = rest[:i] }
	return host != ""
}

Type guard

func ociURLWithNamespace(s string) (ns string, ok bool) {
	rest, has := strings.CutPrefix(s, "oci://")
	if !has { return "", false }
	if i := strings.Index(rest, "/"); i >= 0 { rest = rest[:i] }
	return rest, rest != ""
}

Try / catch

if err := remotecache.ValidateRemoteURL(u); err != nil {
	if strings.Contains(err.Error(), "namespace or bucket host") {
		return fmt.Errorf("oci remote %q must be oci://namespace/bucket/path", u)
	}
}

Prevention

When it happens

Trigger: ValidateRemoteURL with "oci://", "oci:///bucket/path", or a URL missing the namespace host segment.

Common situations: OCI remotes built from templates where the NAMESPACE variable was empty, or copying only the object path from a cloud console URL.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/511b4b8a510813a2. Report an issue: GitHub.