{"record":{"id":"acb3f7c23ea6264a","repo":"ipfs/kubo","slug":"cannot-access-config-repo-not-open","errorCode":null,"errorMessage":"cannot access config, repo not open","messagePattern":"cannot access config, repo not open","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"repo/fsrepo/fsrepo.go","lineNumber":587,"sourceCode":"\tr.closed = true\n\treturn r.lockfile.Close()\n}\n\n// Config the current config. This function DOES NOT copy the config. The caller\n// MUST NOT modify it without first calling `Clone`.\n//\n// Result when not Open is undefined. The method may panic if it pleases.\nfunc (r *FSRepo) Config() (*config.Config, error) {\n\t// It is not necessary to hold the package lock since the repo is in an\n\t// opened state. The package lock is _not_ meant to ensure that the repo is\n\t// thread-safe. The package lock is only meant to guard against removal and\n\t// coordinate the lockfile. However, we provide thread-safety to keep\n\t// things simple.\n\tpackageLock.Lock()\n\tdefer packageLock.Unlock()\n\n\tif r.closed {\n\t\treturn nil, errors.New(\"cannot access config, repo not open\")\n\t}\n\treturn r.config, nil\n}\n\nfunc (r *FSRepo) UserResourceOverrides() (rcmgr.PartialLimitConfig, error) {\n\t// It is not necessary to hold the package lock since the repo is in an\n\t// opened state. The package lock is _not_ meant to ensure that the repo is\n\t// thread-safe. The package lock is only meant to guard against removal and\n\t// coordinate the lockfile. However, we provide thread-safety to keep\n\t// things simple.\n\tpackageLock.Lock()\n\tdefer packageLock.Unlock()\n\n\tif r.closed {\n\t\treturn rcmgr.PartialLimitConfig{}, errors.New(\"cannot access config, repo not open\")\n\t}\n\treturn r.userResourceOverrides, nil\n}","sourceCodeStart":569,"sourceCodeEnd":605,"githubUrl":"https://github.com/ipfs/kubo/blob/329838acdfafae224582930457efe80aa217afc0/repo/fsrepo/fsrepo.go#L569-L605","documentation":"FSRepo.Config returns this when the repo is not open (r.closed is true). Config is an in-memory accessor valid only while the repo is open, so access before Open or after Close fails. The library deliberately refuses instead of returning a zero config.","triggerScenarios":"Calling Config() before Init/Open, or after Close(); holding a stale FSRepo pointer after the node has shut down; calling Config from a goroutine that outlives repo shutdown.","commonSituations":"Plugins or hooks reading config during daemon teardown; tests that close the repo at the top of a helper then read config; using a repo instance recreated by migrations after the old one was closed.","solutions":["Ensure Open() succeeded before accessing Config","Reorder shutdown so config reads happen before Close","Keep a reference to the config value obtained while open instead of reading post-close"],"exampleFix":"// before\nrepo.Close()\ncfg, err := repo.Config()\n// after\ncfg, err := repo.Config()\nif err != nil { return err }\nrepo.Close()","handlingStrategy":"validation","validationCode":"if repoClosed { return errors.New(\"repo not open\") }\ncfg, err := repo.Config()","typeGuard":null,"tryCatchPattern":"cfg, err := repo.Config()\nif err != nil && strings.Contains(err.Error(), \"repo not open\") {\n    // reopen the repo or load config from disk instead\n}","preventionTips":["Only access config between Open and Close","Cache the config value while open","Use repo.Config only on repos you opened"],"tags":["go","lifecycle","repo","config"],"backgroundTag":"resource-already-closed","analyzedSha":"329838acdfafae224582930457efe80aa217afc0","analyzedAt":"2026-09-03T18:30:52.135Z","contentChangedAt":"2026-09-03T18:30:52.135Z","schemaVersion":2},"datasetVersion":"2026-09-11T00:17:11.886Z"}