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.

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.

Appendix: 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)