{"record":{"id":"2dfdd81f3e4441aa","repo":"HangfireIO/Hangfire","slug":"unable-to-obtain-resource-identifier-ex-message","errorCode":null,"errorMessage":"Unable to obtain resource identifier: {ex.Message}","messagePattern":"Unable to obtain resource identifier: (.+?)","errorType":"exception","errorClass":"FormatException","httpStatus":null,"severity":"error","filePath":"src/Hangfire.Core/DisableConcurrentExecutionAttribute.cs","lineNumber":76,"sourceCode":"            {\n                throw new InvalidOperationException(\"Can not release a distributed lock: it was not acquired.\");\n            }\n\n            var distributedLock = (IDisposable)value;\n            distributedLock.Dispose();\n        }\n\n        private string GetResource(Job job)\n        {\n            if (!String.IsNullOrWhiteSpace(Resource))\n            {\n                try\n                {\n                    return String.Format(CultureInfo.InvariantCulture, Resource, job.Args.ToArray()).ToLowerInvariant();\n                }\n                catch (Exception ex)\n                {\n                    throw new FormatException($\"Unable to obtain resource identifier: {ex.Message}\");\n                }\n            }\n\n            return $\"{job.Type.ToGenericTypeString()}.{job.Method.Name}\";\n        }\n    }\n}\n","sourceCodeStart":58,"sourceCodeEnd":84,"githubUrl":"https://github.com/HangfireIO/Hangfire/blob/c236dd0f930f831ec151e436e138ddc429a02a72/src/Hangfire.Core/DisableConcurrentExecutionAttribute.cs#L58-L84","documentation":"DisableConcurrentExecutionAttribute.GetResource (DisableConcurrentExecutionAttribute.cs:76) formats the Resource template using the job's arguments via String.Format(Resource, job.Args.ToArray()). If the Resource string contains format placeholders ({0}, {1}) that do not align with the argument count/types, or contains malformed braces, String.Format throws and the catch re-wraps it as a FormatException with the original message.","triggerScenarios":"Setting [DisableConcurrentExecution(Resource = \"...\", ...)] with a format template whose placeholders ({0}, {1}, etc.) reference indices beyond the job method's argument count, or contain unescaped braces like '{' or '}' that are not valid format items.","commonSituations":"Resource template was written for a different method signature with more arguments; typo in the format string (e.g. 'lock_{0}_{5}' when there are only 2 args); a literal brace in the resource name that String.Format interprets as a placeholder.","solutions":["Ensure the Resource format string's placeholder indices are all within the bounds of the job method's actual parameters.","Escape literal braces by doubling them (use '{{' and '}}') if you need literal curly braces in the resource name.","If no interpolation is needed, omit placeholders entirely and use a plain string."],"exampleFix":"// before: method has 1 arg but template references {1}\n[DisableConcurrentExecution(Resource = \"lock_{0}_{1}\", timeoutSec = 30)]\npublic void Run(int orderId) { ... }\n\n// after\n[DisableConcurrentExecution(Resource = \"lock_{0}\", timeoutSec = 30)]\npublic void Run(int orderId) { ... }","handlingStrategy":"validation","validationCode":"// Validate the Resource template against the job method's parameter count\nstatic void ValidateResourceTemplate(string resource, int argCount)\n{\n    if (string.IsNullOrEmpty(resource)) return;\n    try { string.Format(resource, new object[argCount]); }\n    catch (FormatException ex)\n    {\n        throw new FormatException(\n            $\"Resource template '{resource}' is invalid for {argCount} args: {ex.Message}\");\n    }\n}\n\nValidateResourceTemplate(\"lock_{0}_{1}\", argCount: 1); // throws proactively","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Ensure Resource format placeholders ({0}, {1}) match the job method's argument count.","Escape literal braces as '{{' and '}}' if needed in the resource name.","If no interpolation is needed, use a plain string with no placeholders.","Test resource templates against the actual method signature."],"tags":["concurrency","format-exception","resource-template","attribute"],"backgroundTag":null,"analyzedSha":"c236dd0f930f831ec151e436e138ddc429a02a72","analyzedAt":"2026-08-13T20:27:11.027Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}