AlistGo/alist · critical

access_token is required in token mode

Error message

access_token is required in token mode

What it means

Returned by Terabox.Init (drivers/terabox/driver.go:48) when /api/check/login responds with errno 9000. Terabox uses region-locked domains; 9000 means the terabox.com endpoint is not offered for the region your egress IP appears to be in, so the driver cannot initialize at all.

Source

Thrown at drivers/123_open/client.go:30

	"github.com/alist-org/alist/v3/internal/op"
	pan123 "github.com/okatu-loli/go-123pan"
)

// tokenRefreshMargin is how long before expiry a token is proactively renewed.
const tokenRefreshMargin = 10 * time.Minute

var errNoRefreshCredentials = errors.New("access_token expired: provide a refresh_token together with clientID/clientSecret, or switch to client_credentials mode")

// newSDKClient builds the SDK client for the configured authentication mode.
func (d *Open123) newSDKClient() (*pan123.Client, error) {
	opts := []pan123.Option{
		pan123.WithHTTPClient(&http.Client{Timeout: 60 * time.Second}),
		pan123.WithUserAgent("AList/" + conf.Version),
	}
	switch d.AuthMode {
	case AuthToken:
		if d.AccessToken == "" {
			return nil, errors.New("access_token is required in token mode")
		}
		c := pan123.NewWithToken(d.AccessToken, opts...)
		// expiry is unknown for an externally issued token; refresh on demand
		c.SetToken(d.AccessToken, d.tokenExpiry())
		return c, nil
	case AuthClientCredentials, "":
		if d.ClientID == "" || d.ClientSecret == "" {
			return nil, errors.New("clientID and clientSecret are required in client_credentials mode")
		}
		return pan123.New(d.ClientID, d.ClientSecret, opts...), nil
	default:
		return nil, fmt.Errorf("unknown auth_mode: %s", d.AuthMode)
	}
}

// tokenExpiry reports the stored expiry of an externally issued access token.
// A zero time tells the SDK never to refresh on its own; renewal is driven by
// ensureToken so the rotated refresh_token can be persisted.

View on GitHub (pinned to 843d9dc814)

Solutions

  1. Route the server's traffic through an egress in a supported region (VPN/proxy) so API calls come from an allowed IP.
  2. If available in your region, use the corresponding regional Terabox variant driver/domain instead of www.terabox.com.
  3. Verify with a manual curl to https://www.terabox.com/api/check/login with the configured cookie from the same host to confirm the block is IP-based, not account-based.
  4. Re-check after some time if the geo-block is transient or newly introduced.

Example fix

// before
baseURL := "https://www.terabox.com" // from blocked-region server -> errno 9000

// after: egress via allowed-region proxy
transport := &http.Transport{Proxy: http.ProxyURL(proxyInSupportedRegion)}
client := resty.New().SetTransport(transport)
Defensive patterns

Strategy: fallback

Validate before calling

// probe region availability before mounting
var resp CheckLoginResp
_, err := d.get("/api/check/login", nil, &resp)
if err == nil && resp.Errno == 9000 {
	// route via supported-region egress before adding the storage
}

Try / catch

if err := storage.Init(ctx); err != nil && strings.Contains(err.Error(), "not yet available in this area") {
	// switch egress (VPN/proxy) or use the regional Terabox variant, then retry Init
}

Prevention

When it happens

Trigger: Mounting/initializing the Terabox storage from a server located in a region where Terabox (as opposed to regional variants like 1024tera/Dubox) is unavailable; using a datacenter IP (many datacenter ranges are geo-classified differently than expected); VPN egress changes after the storage was configured.

Common situations: Self-hosting on a VPS in a blocked region; ISP-level geo-routing changes; Terabox tightening its geo-fence so IPs that used to work now get 9000.

Related errors


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