{"record":{"id":"70d9376facbef4fb","repo":"Tencent/WeKnora","slug":"remote-provider-returned-sandbox-q-outside-metada","errorCode":null,"errorMessage":"remote provider returned sandbox %q outside metadata filter","messagePattern":"remote provider returned sandbox %q outside metadata filter","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/sandbox/session_lifecycle.go","lineNumber":303,"sourceCode":"\t\tleft, right := summaries[i], summaries[j]\n\t\tif left.StartedAt.Equal(right.StartedAt) {\n\t\t\treturn left.ID < right.ID\n\t\t}\n\t\tif left.StartedAt.IsZero() {\n\t\t\treturn false\n\t\t}\n\t\tif right.StartedAt.IsZero() {\n\t\t\treturn true\n\t\t}\n\t\treturn left.StartedAt.Before(right.StartedAt)\n\t})\n\n\tfor _, summary := range summaries {\n\t\tif summary.ID == \"\" || summary.State == RemoteStateTerminal {\n\t\t\tcontinue\n\t\t}\n\t\tif !metadataMatches(summary.Metadata, metadata) {\n\t\t\treturn nil, false, fmt.Errorf(\n\t\t\t\t\"remote provider returned sandbox %q outside metadata filter\",\n\t\t\t\tsummary.ID,\n\t\t\t)\n\t\t}\n\t\thandle, err := l.client.Connect(ctx, summary.ID)\n\t\tif err != nil {\n\t\t\tif CanReplaceRemoteBinding(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\treturn nil, false, fmt.Errorf(\"connect owned remote sandbox: %w\", err)\n\t\t}\n\t\tif err := l.validateHandle(handle, summary.ID); err != nil {\n\t\t\treturn nil, false, err\n\t\t}\n\t\tif err := l.cleanupOwnedDuplicates(ctx, summaries, summary.ID, metadata); err != nil {\n\t\t\treturn nil, false, err\n\t\t}\n\t\ttemplateID := summary.TemplateID","sourceCodeStart":285,"sourceCodeEnd":321,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/sandbox/session_lifecycle.go#L285-L321","documentation":"This is a defense-in-depth check: after listing sandboxes by metadata filter, each returned summary's metadata is re-verified locally with metadataMatches. If the provider returns a sandbox whose metadata does not match the requested filter, the library treats it as a provider contract violation and fails rather than connecting to (or cleaning up) a sandbox it does not own.","triggerScenarios":"During recoverOwnedSandbox, a non-terminal summary from client.List has metadata that fails metadataMatches(summary.Metadata, metadata) — i.e. the provider ignored or loosened the metadata filter, or metadata keys/values were altered after creation.","commonSituations":"Providers that match metadata partially or case-insensitively while the local check is exact; provider stripping or re-encoding metadata values; sandboxes created by another tenant/session sharing a prefix of the metadata; provider SDK bug returning unfiltered pages.","solutions":["Compare the returned sandbox's metadata against your filter to find the mismatch (case, encoding, extra/missing keys)","Normalize metadata values at creation time (lowercase, no special characters) so provider and local matching agree","Report/work around the provider's filter semantics — e.g. post-filter locally and skip non-matching IDs instead of erroring, if you control the client","Verify no other workload is creating sandboxes with colliding metadata keys"],"exampleFix":"// before\nmetadata := map[string]string{\"owner\": userEmail} // case varies across services\n// after\nmetadata := map[string]string{\"owner\": strings.ToLower(userEmail)} // stable, exact-match safe","handlingStrategy":"validation","validationCode":"// ensure metadata written at creation matches what filtering expects\nmd := map[string]string{\"session\": key, \"owner\": strings.ToLower(owner)}\nif !sandbox.MetadataMatches(md, sandbox.MetadataFor(key)) {\n    return errors.New(\"metadata would not match recovery filter\")\n}","typeGuard":"func ownedBySession(summary sandbox.RemoteSandboxSummary, md map[string]string) bool {\n    return sandbox.MetadataMatches(summary.Metadata, md)\n}","tryCatchPattern":"handle, err := session.Resolve(ctx, key)\nif err != nil && strings.Contains(err.Error(), \"outside metadata filter\") {\n    // provider returned unfiltered results: normalize metadata and re-resolve\n    handle, err = session.Resolve(ctx, key)\n}","preventionTips":["Normalize metadata values (case, encoding) at creation time","Use highly specific, non-prefix-colliding metadata keys","Test the provider's filter semantics (exact vs partial match)","Avoid sharing metadata key namespaces across workloads"],"tags":["provider-invariant","metadata-filter","sandbox-recovery","data-integrity"],"backgroundTag":"metadata-filter-mismatch","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}