{"record":{"id":"e99c05b3dd6bcd90","repo":"Tencent/WeKnora","slug":"errsandboxconfignotfound","errorCode":"ErrSandboxConfigNotFound","errorMessage":"%w: %s","messagePattern":"%w: %s","errorType":"error_code","errorClass":"ErrSandboxConfigNotFound","httpStatus":null,"severity":"error","filePath":"internal/sandbox/tenant_resolver.go","lineNumber":168,"sourceCode":"\n// Resolve builds the manager from the selected config's current settings.\nfunc (r *tenantSandboxResolver) Resolve(\n\tctx context.Context,\n\ttenantID uint64,\n\tconfigID string,\n) (Manager, error) {\n\tif strings.TrimSpace(configID) == \"\" ||\n\t\tconfigID == types.SandboxConfigIDGlobalDefault {\n\t\treturn NewDisabledManager(), nil\n\t}\n\n\tresolved, err := r.deps.Loader.Load(ctx, tenantID, configID)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\n\t\t\t\"sandbox: load workspace %d config %q: %w\", tenantID, configID, err)\n\t}\n\tif !resolved.Found {\n\t\treturn nil, fmt.Errorf(\"%w: %s\", ErrSandboxConfigNotFound, configID)\n\t}\n\tif resolved.Cordoned {\n\t\treturn nil, fmt.Errorf(\"%w: %s\", ErrSandboxConfigCordoned, configID)\n\t}\n\n\teffective, err := ResolveEffectiveConfig(resolved.Config, r.deps.GlobalConfig)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif err := EnsureDockerBackendAllowed(effective.Type); err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch effective.Type {\n\tcase SandboxTypeDisabled:\n\t\treturn NewDisabledManager(), nil\n\tcase SandboxTypeCube, SandboxTypeE2B, SandboxTypeDocker:\n\t\tclient, err := r.buildClient(effective)","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/sandbox/tenant_resolver.go#L150-L186","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the config ID exists for that tenant (list the tenant's sandbox configs) and use a valid ID.","Create the missing sandbox config for the workspace before resolving.","Handle errors.Is(err, sandbox.ErrSandboxConfigNotFound) by falling back to a default config instead of failing."],"exampleFix":"// before\ncfg, err := resolver.Resolve(ctx, tenantID, cfgID) // cfgID deleted\n// after\ncfg, err := resolver.Resolve(ctx, tenantID, cfgID)\nif errors.Is(err, sandbox.ErrSandboxConfigNotFound) {\n    cfgID = defaultConfigID\n    cfg, err = resolver.Resolve(ctx, tenantID, cfgID)\n}","handlingStrategy":"try-catch","validationCode":"// resolve via listing API before use\nids, _ := client.ListWorkspaceConfigIDs(ctx, tenantID)\nif !slices.Contains(ids, configID) { /* create or pick another config */ }","typeGuard":null,"tryCatchPattern":"cfg, err := resolver.Resolve(ctx, tenantID, configID)\nif errors.Is(err, sandbox.ErrSandboxConfigNotFound) {\n    return provisionDefaultConfig(ctx, tenantID)\n}\nif err != nil { return err }","preventionTips":["Store config IDs as foreign-key references and validate on write.","Clean up references when a config is deleted.","Scope config IDs per tenant to avoid cross-workspace mix-ups."],"tags":["configuration","not-found","multi-tenant"],"backgroundTag":"config-not-found","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}