Tencent/WeKnora · error

unsafe TOS endpoint: %w

Error message

unsafe TOS endpoint: %w

What it means

NewTosFileServiceWithTempBucket validates the TOS endpoint with utils.ValidateURLForSSRF before creating the client; this error wraps that validation failure. The endpoint URL was judged unsafe — e.g. pointing at localhost, a private/link-local IP, or otherwise invalid scheme — to prevent server-side request forgery. Service construction aborts.

Source

Thrown at internal/application/service/file/tos.go:40

// tosFileService implements the FileService interface for Volcengine TOS.
type tosFileService struct {
	client         *tos.ClientV2
	pathPrefix     string
	bucketName     string
	tempBucketName string
}

const tosScheme = "tos://"

// NewTosFileService creates a TOS file service.
func NewTosFileService(endpoint, region, accessKey, secretKey, bucketName, pathPrefix string) (interfaces.FileService, error) {
	return NewTosFileServiceWithTempBucket(endpoint, region, accessKey, secretKey, bucketName, pathPrefix, "", "")
}

// NewTosFileServiceWithTempBucket creates a TOS file service with optional temp bucket.
func NewTosFileServiceWithTempBucket(endpoint, region, accessKey, secretKey, bucketName, pathPrefix, tempBucketName, tempRegion string) (interfaces.FileService, error) {
	if err := utils.ValidateURLForSSRF(endpoint); err != nil {
		return nil, fmt.Errorf("unsafe TOS endpoint: %w", err)
	}
	httpConfig := utils.DefaultSSRFSafeHTTPClientConfig()
	client, err := tos.NewClientV2(
		endpoint,
		tos.WithRegion(region),
		tos.WithCredentials(tos.NewStaticCredentials(accessKey, secretKey)),
		tos.WithHTTPTransport(&utils.SSRFValidatingRoundTripper{
			Base: utils.NewSSRFSafeTransport(httpConfig),
		}),
	)
	if err != nil {
		return nil, fmt.Errorf("failed to initialize TOS client: %w", err)
	}

	if err := ensureTOSBucket(client, bucketName); err != nil {
		return nil, err
	}

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Set the endpoint to a valid public TOS endpoint with proper scheme (e.g. https://tos-cn-beijing.volces.com)
  2. Inspect the wrapped ValidateURLForSSRF error to see which rule (scheme, private IP, loopback) rejected it
  3. If internal endpoints are required, use the sanctioned internal endpoint/allowlist mechanism rather than bypassing SSRF checks
  4. Fix the storage config/env var supplying the endpoint (typos, missing scheme)

Example fix

// before
endpoint := os.Getenv("TOS_ENDPOINT") // "localhost:9000"
svc, err := file.NewTosFileService(endpoint, ...)
// after
endpoint := os.Getenv("TOS_ENDPOINT") // "https://tos-cn-beijing.volces.com"
if u, err := url.Parse(endpoint); err != nil || u.Host == "" {
    return fmt.Errorf("invalid TOS_ENDPOINT %q", endpoint)
}
svc, err := file.NewTosFileService(endpoint, ...)
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(endpoint)
if err != nil || u.Host == "" { return fmt.Errorf("bad endpoint %q", endpoint) }
if err := utils.ValidateURLForSSRF(endpoint); err != nil {
    return fmt.Errorf("endpoint rejected: %w", err)
}

Try / catch

svc, err := file.NewTosFileServiceWithTempBucket(endpoint, ...)
if err != nil && strings.Contains(err.Error(), "unsafe TOS endpoint") {
    log.Fatalf("TOS_ENDPOINT %q failed SSRF validation: %v", endpoint, err)
}

Prevention

When it happens

Trigger: Constructing the TOS service (directly or via NewFileServiceFromStorageConfig/NewTosFileService/initRawFileService) with an endpoint that is http to an internal host, resolves to a private/loopback address, or is an unparseable URL.

Common situations: Config pointing TOS endpoint at 'http://localhost:9000' or an internal IP in dev; typo like 'tos://bucket' instead of a host; missing scheme in the endpoint env var; SSRF guard newly enabled rejecting previously accepted internal endpoints.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/8d507f67f976a2a2. Report an issue: GitHub.