{"record":{"id":"1f761e1d91053a58","repo":"microsoft/aspire","slug":"resource-resource-name-has-a-resource-persistence-mode-but","errorCode":null,"errorMessage":"Resource '{resource.Name}' has a resource persistence mode but no source resource.","messagePattern":"Resource '(.+?)' has a resource persistence mode but no source resource\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting/ApplicationModel/ResourceExtensions.cs","lineNumber":1128,"sourceCode":"        return GetLifetimeType(resource, []);\n    }\n\n    private static Lifetime GetLifetimeType(IResource resource, HashSet<IResource> visitedResources)\n    {\n        if (!visitedResources.Add(resource))\n        {\n            throw new InvalidOperationException($\"A circular lifetime reference was detected for resource '{resource.Name}'.\");\n        }\n\n        if (resource.TryGetLastAnnotation<PersistenceAnnotation>(out var persistenceAnnotation))\n        {\n            return persistenceAnnotation.Mode switch\n            {\n                PersistenceMode.Session => Lifetime.Session,\n                PersistenceMode.Persistent => Lifetime.Persistent,\n                PersistenceMode.Resource => persistenceAnnotation.SourceResource is { } sourceResource\n                    ? GetLifetimeType(sourceResource, visitedResources)\n                    : throw new InvalidOperationException($\"Resource '{resource.Name}' has a resource persistence mode but no source resource.\"),\n                PersistenceMode.ParentProcess => Lifetime.Persistent,\n                _ => throw new InvalidOperationException($\"Unknown persistence mode '{Enum.GetName(typeof(PersistenceMode), persistenceAnnotation.Mode)}'.\")\n            };\n        }\n\n        if (resource.TryGetLastAnnotation<ContainerLifetimeAnnotation>(out var containerLifetimeAnnotation))\n        {\n            return containerLifetimeAnnotation.Lifetime switch\n            {\n                ContainerLifetime.Session => Lifetime.Session,\n                ContainerLifetime.Persistent => Lifetime.Persistent,\n                _ => throw new InvalidOperationException($\"Unknown container lifetime '{Enum.GetName(typeof(ContainerLifetime), containerLifetimeAnnotation.Lifetime)}'.\")\n            };\n        }\n\n        return Lifetime.Session;\n    }\n","sourceCodeStart":1110,"sourceCodeEnd":1146,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting/ApplicationModel/ResourceExtensions.cs#L1110-L1146","documentation":"When a resource's PersistenceAnnotation uses PersistenceMode.Resource, its lifetime is inherited from the annotation's SourceResource. If SourceResource is null, the lifetime cannot be resolved, so GetLifetimeType throws InvalidOperationException.","triggerScenarios":"Creating a PersistenceAnnotation with Mode = PersistenceMode.Resource but without setting SourceResource (or passing null to the API), then resolving the resource lifetime.","commonSituations":"Manually constructing PersistenceAnnotation and forgetting the source; calling a persistence helper overload that omits the source resource while still requesting resource-persistence mode.","solutions":["Supply the source resource when using PersistenceMode.Resource (e.g. pass the resource to the persistence API).","Use PersistenceMode.Session or PersistenceMode.Persistent if no source resource applies.","Validate the annotation's SourceResource before publishing/starting the app model."],"exampleFix":"// before\nbuilder.AddRedis(\"cache\").WithPersistence(PersistenceMode.Resource, source: null);\n// after\nvar db = builder.AddPostgres(\"db\");\nbuilder.AddRedis(\"cache\").WithPersistence(PersistenceMode.Resource, source: db);","handlingStrategy":"validation","validationCode":"if (pa.Mode == PersistenceMode.Resource && pa.SourceResource is null) throw new InvalidOperationException(\"PersistenceMode.Resource requires a SourceResource\");","typeGuard":"bool HasSource(PersistenceAnnotation pa) => pa.Mode != PersistenceMode.Resource || pa.SourceResource is not null;","tryCatchPattern":"try { var lifetime = resource.GetLifetimeType(); } catch (InvalidOperationException ex) when (ex.Message.Contains(\"no source resource\")) { /* fix annotation, add source */ throw; }","preventionTips":["Use helper APIs that require the source parameter rather than building PersistenceAnnotation by hand.","Match the mode to the wiring: no source means Session/Persistent/ParentProcess.","Add a model-validation pass before builder.Build() in large app hosts."],"tags":["aspire","persistence","missing-argument","model-validation"],"backgroundTag":"missing-required-argument","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}