Tencent/WeKnora · error · ErrSandboxConfigNotFound

ErrSandboxConfigNotFound

ErrSandboxConfigNotFound

Error message

%w: %s

What it means

The tenant resolver's Resolve loads a workspace sandbox config from the configured loader. If the loader reports not Found, Resolve returns this sentinel-wrapped error (ErrSandboxConfigNotFound) carrying the config ID, so callers can distinguish 'missing' from 'load failed' via errors.Is.

Source

Thrown at internal/sandbox/tenant_resolver.go:168

// Resolve builds the manager from the selected config's current settings.
func (r *tenantSandboxResolver) Resolve(
	ctx context.Context,
	tenantID uint64,
	configID string,
) (Manager, error) {
	if strings.TrimSpace(configID) == "" ||
		configID == types.SandboxConfigIDGlobalDefault {
		return NewDisabledManager(), nil
	}

	resolved, err := r.deps.Loader.Load(ctx, tenantID, configID)
	if err != nil {
		return nil, fmt.Errorf(
			"sandbox: load workspace %d config %q: %w", tenantID, configID, err)
	}
	if !resolved.Found {
		return nil, fmt.Errorf("%w: %s", ErrSandboxConfigNotFound, configID)
	}
	if resolved.Cordoned {
		return nil, fmt.Errorf("%w: %s", ErrSandboxConfigCordoned, configID)
	}

	effective, err := ResolveEffectiveConfig(resolved.Config, r.deps.GlobalConfig)
	if err != nil {
		return nil, err
	}
	if err := EnsureDockerBackendAllowed(effective.Type); err != nil {
		return nil, err
	}

	switch effective.Type {
	case SandboxTypeDisabled:
		return NewDisabledManager(), nil
	case SandboxTypeCube, SandboxTypeE2B, SandboxTypeDocker:
		client, err := r.buildClient(effective)

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Verify the config ID exists for that tenant (list the tenant's sandbox configs) and use a valid ID.
  2. Create the missing sandbox config for the workspace before resolving.
  3. Handle errors.Is(err, sandbox.ErrSandboxConfigNotFound) by falling back to a default config instead of failing.

Example fix

// before
cfg, err := resolver.Resolve(ctx, tenantID, cfgID) // cfgID deleted
// after
cfg, err := resolver.Resolve(ctx, tenantID, cfgID)
if errors.Is(err, sandbox.ErrSandboxConfigNotFound) {
    cfgID = defaultConfigID
    cfg, err = resolver.Resolve(ctx, tenantID, cfgID)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// resolve via listing API before use
ids, _ := client.ListWorkspaceConfigIDs(ctx, tenantID)
if !slices.Contains(ids, configID) { /* create or pick another config */ }

Try / catch

cfg, err := resolver.Resolve(ctx, tenantID, configID)
if errors.Is(err, sandbox.ErrSandboxConfigNotFound) {
    return provisionDefaultConfig(ctx, tenantID)
}
if err != nil { return err }

Prevention

When it happens

Trigger: Calling Resolve with a tenantID/configID pair for which deps.Loader.Load returns resolved.Found == false — e.g. a config ID that was never created or was deleted for that tenant.

Common situations: Stale config IDs cached in application settings after deletion; cross-tenant ID mix-ups (config belongs to another workspace); typos in the config ID; environments where seed configs were never provisioned.

Related errors


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