{"record":{"id":"5c5fd5d7c0fb3010","repo":"Tencent/WeKnora","slug":"sandbox-config-is-missing-required-fields","errorCode":null,"errorMessage":"sandbox: config is missing required fields","messagePattern":"sandbox: config is missing required fields","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"internal/sandbox/config_required.go","lineNumber":29,"sourceCode":"//   - Values the SDK resolves by itself. go-e2b defaults both the API base URL\n//     and the sandbox domain when they are left empty, so demanding them would\n//     force operators to spell out constants they cannot verify.\n//\n// Everything else is required precisely because its absence fails late and\n// obscurely: a missing Cube proxy URL or sandbox domain still creates a sandbox\n// and only breaks when envd traffic is routed, which reads as a provider outage\n// rather than a typo in the form.\npackage sandbox\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n)\n\n// ErrSandboxConfigIncomplete marks a named config that cannot build a working\n// client because required fields are empty. Callers map it onto 400.\nvar ErrSandboxConfigIncomplete = errors.New(\"sandbox: config is missing required fields\")\n\n// MissingRequiredFields lists the fields cfg fails to supply for its own\n// provider, named after the JSON keys the API and the settings form use so the\n// message can be surfaced without translation. Disabled holds no\n// backend-specific values; Docker must explicitly name its image.\nfunc MissingRequiredFields(cfg *Config) []string {\n\tif cfg == nil {\n\t\treturn nil\n\t}\n\tvar missing []string\n\trequire := func(field, value string) {\n\t\tif strings.TrimSpace(value) == \"\" {\n\t\t\tmissing = append(missing, field)\n\t\t}\n\t}\n\tswitch cfg.Type {\n\tcase SandboxTypeCube:\n\t\trequire(\"api_url\", cfg.CubeAPIURL)","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/sandbox/config_required.go#L11-L47","documentation":"ErrSandboxConfigIncomplete marks a named sandbox config that cannot build a working client because required fields for its provider (Cube, E2B, Docker, etc.) are empty. MissingRequiredFields lists the offending fields using the JSON key names shown in the API/settings form, so the message can be surfaced directly to users. Callers map it onto HTTP 400.","triggerScenarios":"Saving, sanitizing, probing, or resolving a tenant sandbox config where a mandatory provider field is blank — e.g. a Cube config missing proxy_url, an E2B config missing its API key, or a Docker config without an image name.","commonSituations":"Admin partially fills the sandbox settings form and saves; env-driven config missing required variables; config imported/ copied between tenants with provider-specific fields dropped; Docker image name never set after switching provider to docker.","solutions":["Open the sandbox settings for the tenant and fill every field listed in the error message (e.g. proxy_url, image).","Call sandbox.MissingRequiredFields(cfg) before saving/resolving to get the exact missing JSON keys and show them in the UI.","If the field is intentionally unset, switch the config's provider to one whose required fields are satisfied, or disable the sandbox.","Verify via tests that SanitizeSandboxConfig/Resolve paths return ErrSandboxConfigIncomplete early with the field name in the message."],"exampleFix":"// before: saving incomplete cube config\nincoming := &sandbox.Config{Provider: \"cube\"} // proxy_url empty\n_, err := SanitizeSandboxConfig(incoming, nil) // -> ErrSandboxConfigIncomplete (proxy_url)\n// after: validate and surface missing fields first\nif missing := sandbox.MissingRequiredFields(incoming); len(missing) > 0 {\n    return fmt.Errorf(\"sandbox config missing: %s\", strings.Join(missing, \", \"))\n}\n_, err := SanitizeSandboxConfig(incoming, nil)","handlingStrategy":"validation","validationCode":"if missing := sandbox.MissingRequiredFields(cfg); len(missing) > 0 {\n    return fmt.Errorf(\"%w: missing %s\",\n        sandbox.ErrSandboxConfigIncomplete, strings.Join(missing, \", \"))\n}","typeGuard":"func sandboxConfigComplete(cfg *sandbox.Config) bool {\n    return len(sandbox.MissingRequiredFields(cfg)) == 0\n}","tryCatchPattern":"if err != nil {\n    if errors.Is(err, sandbox.ErrSandboxConfigIncomplete) {\n        // 400 with the field names from the message\n        http.Error(w, err.Error(), http.StatusBadRequest)\n        return\n    }\n}","preventionTips":["Call MissingRequiredFields before every save/resolve.","Mark required fields as required in the settings form schema.","Test each provider's config with empty fields in CI.","When switching provider, reset/reprompt for provider-specific fields."],"tags":["sandbox","config","validation"],"backgroundTag":"schema-validation-failed","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}