{"record":{"id":"7eaf367fce35d98b","repo":"hashicorp/nomad","slug":"missing-allocid","errorCode":null,"errorMessage":"missing AllocID","messagePattern":"missing AllocID","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/client_alloc_endpoint.go","lineNumber":111,"sourceCode":"\t// the Node registration and the cost is fairly high for adding another hope\n\t// in the forwarding chain.\n\targs.QueryOptions.AllowStale = true\n\n\tauthErr := a.srv.Authenticate(nil, args)\n\n\t// Potentially forward to a different region.\n\tif done, err := a.srv.forward(\"ClientAllocations.Signal\", args, args, reply); done {\n\t\treturn err\n\t}\n\ta.srv.MeasureRPCRate(\"client_allocations\", structs.RateMetricWrite, args)\n\tif authErr != nil {\n\t\treturn structs.ErrPermissionDenied\n\t}\n\tdefer metrics.MeasureSince([]string{\"nomad\", \"client_allocations\", \"signal\"}, time.Now())\n\n\t// Verify the arguments.\n\tif args.AllocID == \"\" {\n\t\treturn errors.New(\"missing AllocID\")\n\t}\n\n\t// Find the allocation\n\tsnap, err := a.srv.State().Snapshot()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\talloc, err := getAlloc(snap, args.AllocID)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Check namespace alloc-lifecycle permission.\n\tif aclObj, err := a.srv.ResolveACL(args); err != nil {\n\t\treturn err\n\t} else if !aclObj.AllowNsOp(alloc.Namespace, acl.NamespaceCapabilityAllocLifecycle) {\n\t\treturn structs.ErrPermissionDenied","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/client_alloc_endpoint.go#L93-L129","documentation":"The Signal RPC validates args.AllocID immediately after ACL checks and metrics setup. When AllocID is the empty string the request cannot identify which allocation's task to signal, so the server returns \"missing AllocID\" without further processing. It is a precondition check before state-store lookup and client forwarding.","triggerScenarios":"Calling ClientAllocations.Signal with a structs.AllocSpecificRequest whose AllocID is \"\".","commonSituations":"Sending a signal from a script/API where the allocation ID variable was empty; job tooling that captured an empty alloc ID from a failed prior lookup; zero-valued request structs in automation.","solutions":["Set args.AllocID to the allocation's UUID before calling Signal.","Look up the allocation ID via the Job Allocations API or alloc list if unknown.","Validate AllocID is non-empty in caller code before the RPC."],"exampleFix":"// before\nargs := structs.AllocSpecificRequest{}\nerr := client.Signal(args, &structs.GenericResponse{})\n// after\nargs := structs.AllocSpecificRequest{AllocID: alloc.ID}\nerr := client.Signal(args, &structs.GenericResponse{})","handlingStrategy":"validation","validationCode":"if allocID == \"\" {\n    return fmt.Errorf(\"signal requires a non-empty AllocID\")\n}","typeGuard":"func hasAllocID(args *structs.AllocSpecificRequest) bool {\n    return args != nil && args.AllocID != \"\"\n}","tryCatchPattern":null,"preventionTips":["Store allocation IDs from successful lookups, never hand-type them.","Validate AllocID before every AllocSpecificRequest RPC.","For signal automation, derive the alloc ID from the job allocations API at runtime."],"tags":["nomad","rpc","argument-validation","allocation"],"backgroundTag":"missing-required-argument","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}