{"record":{"id":"1b7d8ecf175b0ab6","repo":"dagger/dagger","slug":"missing-engine-locker","errorCode":null,"errorMessage":"missing engine locker","messagePattern":"missing engine locker","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/container_exec.go","lineNumber":571,"sourceCode":"\tActiveRef       bkcache.MutableRef\n\tOutputMutable   bkcache.MutableRef\n\tOutputImmutable bkcache.ImmutableRef\n}\n\ntype materializedExecPlan struct {\n\tRoot   executor.Mount\n\tMounts []executor.Mount\n\tStates []*execMountState\n}\n\nfunc lockMountedCaches(ctx context.Context, mounts []ContainerMount) (func(), error) {\n\tquery, err := CurrentQuery(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"get current query for cache locks: %w\", err)\n\t}\n\tlocker := query.Locker()\n\tif locker == nil {\n\t\treturn nil, fmt.Errorf(\"missing engine locker\")\n\t}\n\n\tlockSet := make(map[string]struct{})\n\tfor i, ctrMount := range mounts {\n\t\tif ctrMount.Readonly || ctrMount.CacheSource == nil || ctrMount.CacheSource.Volume.Self() == nil {\n\t\t\tcontinue\n\t\t}\n\t\tcacheSelf := ctrMount.CacheSource.Volume.Self()\n\t\tif !cacheSharingModeLocksWrites(cacheSelf.Sharing) {\n\t\t\tcontinue\n\t\t}\n\t\tlockKey, err := cacheSelf.lockKey()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"cache lock key for mount %d: %w\", i, err)\n\t\t}\n\t\tlockSet[lockKey] = struct{}{}\n\t}\n\tif len(lockSet) == 0 {","sourceCodeStart":553,"sourceCodeEnd":589,"githubUrl":"https://github.com/dagger/dagger/blob/82ba2681dbe30d3547a1dc50ea495900ab5b6047/core/container_exec.go#L553-L589","documentation":"After obtaining the query, lockMountedCaches requires the engine's locker (query.Locker()) to serialize cache volume access. If the locker is nil the engine cannot grant cache locks and this error is returned, preventing unsafe concurrent cache writes.","triggerScenarios":"Executing a container with writable cache mounts while the engine session has no locker configured (locker-less engine or misinitialized query).","commonSituations":"Running core exec code outside a fully initialized engine, or engine configurations that skip locker setup (e.g. certain embedded/test setups).","solutions":["Run through a fully initialized dagger engine session where the locker is configured","Check engine initialization code so Locker() is set on the query","If the mounts don't need write-locking semantics, mark them readonly or remove the cache mount"],"exampleFix":"// before\nquery without locker -> startContainer with cache share SHARED\n// after\ninitialize engine locker before exec, or set cache sharing to PRIVATE/LOCKED-free readonly mount","handlingStrategy":"validation","validationCode":"if q.Locker() == nil { return errors.New(\"engine locker unavailable\") }","typeGuard":"func lockerReady(q *Query) bool { return q.Locker() != nil }","tryCatchPattern":null,"preventionTips":["Initialize engine locker before running execs","Mark cache mounts readonly when write locks aren't needed","Avoid locker-less embedded setups for cache-sharing execs"],"tags":["dagger","cache","locking","engine"],"backgroundTag":"missing-engine-locker","analyzedSha":"82ba2681dbe30d3547a1dc50ea495900ab5b6047","analyzedAt":"2026-09-05T07:21:37.930Z","contentChangedAt":"2026-09-05T07:21:37.930Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}