{"record":{"id":"bec34572a38aee1a","repo":"ipfs/kubo","slug":"reading-repo-config-w","errorCode":null,"errorMessage":"reading repo config: %w","messagePattern":"reading repo config: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"core/node/provider.go","lineNumber":455,"sourceCode":"\t\t}\n\t\treturn spec\n\tdefault:\n\t\tif _, hasChild := spec[\"child\"]; hasChild {\n\t\t\tproviderLog.Warnw(\"unrecognized datastore wrapper type, using as-is\",\n\t\t\t\t\"type\", spec[\"type\"])\n\t\t}\n\t\treturn spec\n\t}\n}\n\n// MountKeystoreDatastores opens any provider keystore datastores that exist on\n// disk and returns them as mount.Mount entries ready to be combined with the\n// main repo datastore. The caller must call the returned cleanup function when\n// done. Returns nil mounts and a no-op closer if no keystores exist.\nfunc MountKeystoreDatastores(repo repo.Repo) ([]mount.Mount, func(), error) {\n\tcfg, err := repo.Config()\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"reading repo config: %w\", err)\n\t}\n\n\trootSpec := findRootDatastoreSpec(cfg.Datastore.Spec)\n\tif rootSpec == nil {\n\t\treturn nil, func() {}, nil\n\t}\n\n\tkeystoreBasePath := filepath.Join(repo.Path(), KeystoreDatastorePath)\n\tvar mounts []mount.Mount\n\tvar closers []func()\n\n\tfor _, suffix := range []string{\"0\", \"1\"} {\n\t\tdir := filepath.Join(keystoreBasePath, suffix)\n\t\tif _, err := os.Stat(dir); err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tds, err := openDatastoreAt(rootSpec, dir)\n\t\tif err != nil {","sourceCodeStart":437,"sourceCodeEnd":473,"githubUrl":"https://github.com/ipfs/kubo/blob/329838acdfafae224582930457efe80aa217afc0/core/node/provider.go#L437-L473","documentation":"MountKeystoreDatastores reads the repo configuration to locate the root datastore spec before mounting the alternating keystore datastores. If repo.Config() fails, the error is wrapped as \"reading repo config: %w\" so the underlying cause (lock, corruption, permissions, malformed file) is preserved. It is raised during node construction, in the openDiagDatastore path, so a node startup failure with this message means the repo itself could not be read, not that the keystore logic failed.","triggerScenarios":"Calling MountKeystoreDatastores(repo) (directly or via openDiagDatastore during daemon startup) when the underlying repo.Config() call errors — e.g. repo locked by another process, config file unreadable, invalid JSON, or unsupported config version.","commonSituations":"Two daemons running against the same IPFS_PATH (repo lock held); ~/.ipfs/config corrupted by a partial edit or disk-full write; wrong IPFS_PATH pointing at a non-repo directory; permission problems after running the daemon as different users.","solutions":["Read the wrapped cause at the end of the error chain and fix that specific problem first (it names the real failure).","Check for a stale repo lock: ensure no other ipfs daemon is running (pkill -f \"ipfs daemon\") and remove the lockfile only if no process holds it.","Verify IPFS_PATH points at an initialized repo and that $IPFS_PATH/config is valid JSON (ipfs config show).","Fix file permissions/ownership on the config file so the current user can read it.","If the config is corrupted, restore from backup or re-init the repo (data loss risk — copy the datastore first)."],"exampleFix":"// before (diagnostic)\ncfg, err := repo.Config()\nif err != nil {\n    return nil, nil, fmt.Errorf(\"reading repo config: %w\", err)\n}\n// after (caller-side guard)\ncfg, err := repo.Config()\nif err != nil {\n    if errors.Is(err, fsrepo.ErrNoRepo) {\n        return nil, nil, fmt.Errorf(\"IPFS_PATH is not an initialized repo: %w\", err)\n    }\n    return nil, nil, fmt.Errorf(\"reading repo config: %w\", err)\n}","handlingStrategy":"try-catch","validationCode":"// Before starting the daemon/purge:\nif _, err := os.Stat(filepath.Join(os.Getenv(\"IPFS_PATH\"), \"config\")); err != nil {\n    return fmt.Errorf(\"no repo config at IPFS_PATH=%s: %w\", os.Getenv(\"IPFS_PATH\"), err)\n}\nif _, err := os.Stat(filepath.Join(os.Getenv(\"IPFS_PATH\"), \"repo.lock\")); err == nil {\n    // lock present: verify no live daemon before proceeding\n    log.Warn(\"repo.lock exists; ensure no other daemon is running\")\n}","typeGuard":null,"tryCatchPattern":"cfg, err := repo.Config()\nif err != nil {\n    var cause error = err\n    for errors.Unwrap(cause) != nil { cause = errors.Unwrap(cause) }\n    switch {\n    case errors.Is(err, fsrepo.ErrNoRepo):\n        // IPFS_PATH not initialized: run `ipfs init`\n    case errors.Is(err, syscall.EACCES) || errors.Is(err, syscall.EPERM):\n        // fix file ownership/permissions on IPFS_PATH\n    default:\n        // check repo.lock / corrupted config JSON\n    }\n    return fmt.Errorf(\"reading repo config: %w\", err)\n}","preventionTips":["Never run two daemons against the same IPFS_PATH","Set IPFS_PATH explicitly in scripts and test harnesses","Validate config JSON after hand edits with `ipfs config show`","Back up $IPFS_PATH/config before upgrades or profile changes"],"tags":["go","config","repo","startup"],"backgroundTag":"repo-config-unreadable","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"}