{"record":{"id":"0629d779fa7d2c05","repo":"microsoft/aspire","slug":"random-walk-offset-must-be-within-the-configured-range-size","errorCode":null,"errorMessage":"Random walk offset must be within the configured range size.","messagePattern":"Random walk offset must be within the configured range size\\.","errorType":"exception","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting/Dcp/ProxylessEndpointPortAllocator.cs","lineNumber":69,"sourceCode":"    {\n    }\n\n    internal ProxylessEndpointPortAllocator(int rangeStart, int rangeEnd, Random random, Func<int, ProtocolType, bool> tryProbe)\n        : this(rangeStart, rangeEnd, GetRandomOffset(random, rangeStart, rangeEnd), GetRandomCoprimeStep(random, GetRangeSize(rangeStart, rangeEnd)), tryProbe)\n    {\n    }\n\n    internal ProxylessEndpointPortAllocator(int rangeStart, int rangeEnd, int randomWalkOffset, int randomWalkStep, Func<int, ProtocolType, bool> tryProbe)\n    {\n        PortRange.ValidateRange(rangeStart, rangeEnd, nameof(rangeStart), nameof(rangeEnd));\n\n        _rangeStart = rangeStart;\n        _rangeEnd = rangeEnd;\n        _rangeSize = rangeEnd - rangeStart + 1;\n\n        if (randomWalkOffset < 0 || randomWalkOffset >= _rangeSize)\n        {\n            throw new ArgumentOutOfRangeException(nameof(randomWalkOffset), randomWalkOffset, \"Random walk offset must be within the configured range size.\");\n        }\n\n        if (randomWalkStep < 1 || randomWalkStep > _rangeSize || GreatestCommonDivisor(randomWalkStep, _rangeSize) != 1)\n        {\n            throw new ArgumentOutOfRangeException(nameof(randomWalkStep), randomWalkStep, \"Random walk step must be coprime with the configured range size.\");\n        }\n\n        // The scan range is dense and bounded, so indexable visited state is cheaper and simpler than\n        // hashing individual ports. The default range is only about 23 KB while still giving O(1)\n        // lookups for both random-walk and incremental scans.\n        _visited = new bool[_rangeSize];\n        _randomWalkCursor = randomWalkOffset;\n        _randomWalkStep = randomWalkStep;\n        _tryProbe = tryProbe;\n    }\n\n    public int AllocatePort(EndpointAnnotation endpoint)\n    {","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting/Dcp/ProxylessEndpointPortAllocator.cs#L51-L87","documentation":"Thrown in the ProxylessEndpointPortAllocator constructor when the randomWalkOffset is negative or greater than or equal to the computed range size (rangeEnd - rangeStart + 1). The allocator uses offset + coprime step to walk the port range deterministically, so the offset must land inside the range.","triggerScenarios":"Constructing ProxylessEndpointPortAllocator with a randomWalkOffset outside [0, rangeSize), e.g. offset 50000 against a 1024-port range, or an offset persisted from a previous configuration with a different (smaller) range.","commonSituations":"Persisted allocator state (offset) reused after shrinking the configured port range via env/config; computing the offset from a hash modulo the wrong size; off-by-one using offset == rangeSize.","solutions":["Clamp the offset before construction: randomWalkOffset % (rangeEnd - rangeStart + 1).","Recompute the offset from the current range rather than reusing persisted state from an older configuration.","Validate that offset < rangeEnd - rangeStart + 1 in the config-loading code with a clear error."],"exampleFix":"// before\nvar allocator = new ProxylessEndpointPortAllocator(rangeStart, rangeEnd, offset: 50000);\n// after\nvar rangeSize = rangeEnd - rangeStart + 1;\nvar allocator = new ProxylessEndpointPortAllocator(rangeStart, rangeEnd, offset: offset % rangeSize);","handlingStrategy":"validation","validationCode":"var rangeSize = rangeEnd - rangeStart + 1;\nif (offset < 0 || offset >= rangeSize)\n    offset %= rangeSize; // clamp into the current range","typeGuard":null,"tryCatchPattern":"try { var alloc = new ProxylessEndpointPortAllocator(start, end, offset); }\ncatch (ArgumentOutOfRangeException ex) when (ex.ParamName == nameof(offset)) { offset = 0; /* reseed for this range */ }","preventionTips":["Recompute persisted offsets whenever the port range configuration changes.","Derive the offset as hash % rangeSize so it is always in range.","Store the range alongside the offset and invalidate state when they disagree."],"tags":["ports","allocator","argument-out-of-range"],"backgroundTag":"value-out-of-range","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T09:17:21.228Z"}