{"record":{"id":"d079142c8d3f9ee5","repo":"googleapis/mcp-toolbox","slug":"failed-to-read-manual-prm-file-at-startup-w","errorCode":null,"errorMessage":"failed to read manual PRM file at startup: %w","messagePattern":"failed to read manual PRM file at startup: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/server/server.go","lineNumber":561,"sourceCode":"\tr.Use(hostCheck(allowedHostsMap))\n\n\t// Host OAuth Protected Resource Metadata endpoint\n\tmcpAuthEnabled := false\n\tfor _, authSvc := range s.PrimitiveMgr.AuthServices() {\n\t\tif mSvc, ok := authSvc.(auth.MCPAuthService); ok && mSvc.IsMCPEnabled() {\n\t\t\tmcpAuthEnabled = true\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// Manual PRM override\n\tvar cachedPrmBytes []byte\n\tvar prmConfig ProtectedResourceMetadata\n\tif s.mcpPrmFile != \"\" {\n\t\tvar err error\n\t\tcachedPrmBytes, err = os.ReadFile(s.mcpPrmFile)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to read manual PRM file at startup: %w\", err)\n\t\t}\n\t\t// Unmarshal into the struct to strictly validate the schema\n\t\tif err := json.Unmarshal(cachedPrmBytes, &prmConfig); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"manual PRM file does not match expected schema: %w\", err)\n\t\t}\n\t}\n\n\t// Register route if auth is enabled or a manual file is provided\n\tif mcpAuthEnabled || s.mcpPrmFile != \"\" {\n\t\tr.Get(prmURL.Path, func(w http.ResponseWriter, req *http.Request) {\n\t\t\t// Serve from memory if file was loaded\n\t\t\tif s.mcpPrmFile != \"\" {\n\t\t\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t\tif _, err := w.Write(cachedPrmBytes); err != nil {\n\t\t\t\t\ts.logger.ErrorContext(req.Context(), \"failed to write manual PRM file response\", \"error\", err)\n\t\t\t\t}\n\t\t\t\treturn","sourceCodeStart":543,"sourceCodeEnd":579,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/server/server.go#L543-L579","documentation":"When --prm-file (s.mcpPrmFile) is provided, NewServer reads that file at startup to pre-cache Protected Resource Metadata and strictly validate its JSON schema. A missing, unreadable, or permission-denied file aborts server startup with this wrapped os.ReadFile error.","triggerScenarios":"Starting the server with a PRM file path that does not exist, points to a directory, or is unreadable by the process user (os.ReadFile error) in NewServer.","commonSituations":"K8s/Docker mounts where the secret file path is wrong or the volume failed to mount, relative paths resolved against a different working directory in containers, or wrong file permissions after mounting.","solutions":["Verify the path passed to --prm-file exists and is a regular file (ls -l) inside the container/working directory.","Use an absolute path for the PRM file in containerized deployments.","Check file permissions/ownership so the toolbox process user can read it.","Confirm the volume/secret mount succeeded before the process starts."],"exampleFix":"// before\ntoolbox serve --prm-file ./config/prm.json ...\n// (running from a different cwd in the container)\n\n// after\ntoolbox serve --prm-file /etc/toolbox/prm.json ...","handlingStrategy":"validation","validationCode":"info, err := os.Stat(prmFilePath)\nif err != nil {\n    return fmt.Errorf(\"PRM file %q not accessible: %w\", prmFilePath, err)\n}\nif info.IsDir() {\n    return fmt.Errorf(\"PRM path %q is a directory\", prmFilePath)\n}\nif _, err := os.ReadFile(prmFilePath); err != nil {\n    return fmt.Errorf(\"PRM file unreadable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if _, err := server.NewServer(ctx, cfg); err != nil {\n    var pathErr *os.PathError\n    if errors.As(err, &pathErr) {\n        log.Printf(\"check PRM file path/permissions: %s\", pathErr.Path)\n    }\n    return err\n}","preventionTips":["Use absolute paths for --prm-file in containers.","Ensure the volume/secret mounting the PRM file is healthy before process start (init container check).","Validate the PRM JSON schema in CI with a JSON schema check.","Set readable file permissions (0444) on mounted secrets."],"tags":["go","file-io","oauth","configuration"],"backgroundTag":"file-not-found","analyzedSha":"8cc6e09de2ad7b8bffc77751799585a1401a48eb","analyzedAt":"2026-09-05T01:10:36.887Z","contentChangedAt":"2026-09-05T01:10:36.887Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}