AlistGo/alist · error

cannot write to non-branch reference

Error message

cannot write to non-branch reference

What it means

MakeDir() (and every write operation) checks d.isOnBranch first: writes are only possible when the configured ref resolved to an actual branch. If the storage was configured with a tag name, a commit SHA, or a non-branch ref, the GitHub API cannot create commits on it, so the driver rejects the operation up front. drivers/github/driver.go:188.

Source

Thrown at drivers/github/driver.go:188

	if err != nil {
		return nil, err
	}
	if obj.Type == "submodule" {
		return nil, errors.New("cannot download a submodule")
	}
	url := obj.DownloadURL
	ghProxy := strings.TrimSpace(d.Addition.GitHubProxy)
	if ghProxy != "" {
		url = strings.Replace(url, "https://raw.githubusercontent.com", ghProxy, 1)
	}
	return &model.Link{
		URL: url,
	}, nil
}

func (d *Github) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {
	if !d.isOnBranch {
		return errors.New("cannot write to non-branch reference")
	}
	d.commitMutex.Lock()
	defer d.commitMutex.Unlock()
	parent, err := d.get(parentDir.GetPath())
	if err != nil {
		return err
	}
	if parent.Entries == nil {
		return errs.NotFolder
	}
	subDirSha, err := d.newTree("", []interface{}{
		map[string]string{
			"path":    ".gitkeep",
			"mode":    "100644",
			"type":    "blob",
			"content": "",
		},
	})

View on GitHub (pinned to 843d9dc814)

Solutions

  1. Change the storage's ref configuration to a real branch name (e.g. main or master) and re-save.
  2. Leave ref empty so the driver uses the repo's default branch.
  3. If a read-only mount on a tag is intended, treat this error as expected and avoid write operations.

Example fix

// before (storage config)
Ref: "v1.2.3"

// after
Ref: "main"
Defensive patterns

Strategy: validation

Validate before calling

// after Init resolves the ref
if !d.isOnBranch {
    return errors.New("github storage ref is not a branch; write operations disabled")
}

Type guard

func (d *Github) canWrite() bool { return d.isOnBranch }

Try / catch

if err := d.MakeDir(ctx, parent, name); err != nil && err.Error() == "cannot write to non-branch reference" {
    // surface 'read-only mount (tag/SHA ref)' to the user
}

Prevention

When it happens

Trigger: Calling MakeDir on a storage whose ref field is a tag (e.g. v1.0.0), a 40-hex commit SHA, or 'HEAD' detached — anything where getRepo()/ref resolution did not land on a branch.

Common situations: User pins the mount to a release tag for stability and then tries to create a folder through the UI; ref set to a commit SHA for reproducibility; fork mounted at a non-default ref that is actually a tag.

Related errors


AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15). Data as JSON: /api/errors/9e013edc6530ecf0. Report an issue: GitHub.